Dependencies 如何与在GUI中使用注释值的提供程序绑定?
是否有任何方法可以绑定在GoogleGuice中解释目标注释值的提供者 例如:Dependencies 如何与在GUI中使用注释值的提供程序绑定?,dependencies,guice,code-injection,Dependencies,Guice,Code Injection,是否有任何方法可以绑定在GoogleGuice中解释目标注释值的提供者 例如: bind(Resource.class) .annotatedWith(MyAnnotation.class) .toProvider(new MyProvider<MyAnnotation, Resource>{ public Resource get(MyAnnotation anno){ return resolveResourceByAnno
bind(Resource.class)
.annotatedWith(MyAnnotation.class)
.toProvider(new MyProvider<MyAnnotation, Resource>{
public Resource get(MyAnnotation anno){
return resolveResourceByAnnoValue(anno.value());
}
});
我想以声明的方式绑定UI及其字段,而不是像上面那样务实:
@ResourceID(R.layout.activity_test)
public class TestActivity extends InjectiveActivity{
@ResourceID(R.id.textView) // Auto generated static resource id constant
private TextView textView;
@ResourceID(R.id.testButton)
private Button testButton;
...
}
这是不可能的 如果
@MyAnnotation
是绑定批注,则将使用其equals
方法对其进行比较@MyAnnotation(5)资源
将绑定到@MyAnnotation(5)资源
,与@MyAnnotation(6)资源
相比,该资源根本不匹配。查看更多信息。在这个答案中,如果您愿意,您可以循环使用可能的注释值并单独绑定每个值
如果@MyAnnotation
不是绑定批注,您将无法从提供商处访问它。如中所述,将注入站点信息添加到提供者或依赖项本身
最好是创建一个(或手动工厂)来接受参数:
class MyConsumer {
final Resource resource;
@Inject MyConsumer(Resource.Factory resourceFactory) {
int previouslyAnnotatedValue = 5;
this.resource = resourceFactory.createWithValue(previouslyAnnotatedValue);
}
}
您也可以考虑使用,它将允许您使用除<代码> @注销< /C>以外的任意注释,它可以使用运行时注释值,但是您希望。
< P>这是斯卡拉的示例(我喜欢使用Scala原型,毕竟它是java的一种不同的服装),我在中想了一下之后想出了这个例子。这只会插入名为的
@的值,但看起来效果非常好。这是不可能的。Android SDK生成资源id常量,因此我尝试通过@MyAnnotation(resourceId)
将实际资源注入字段,而不是使用findViewById()
手动分配。由于我不能手动创建资源实例,因为它必须由Android应用程序上下文解析,所以我不能使用工厂或辅助注入方法。无论如何,在提供者中是否没有办法动态解释注释值?我可以使用您所说的循环可比较注释,但我必须通过Java反射迭代生成的资源常量。我闻到了床上的味道(我认为我应该编写自己的注入机制,而不是使用Google Guice。我很好奇为什么Guice没有符合我要求的绑定配置。我不确定我是否理解你所说的“因为我不能手动创建资源实例,因为它必须由安卓应用程序上下文解决”的意思。”:您仍然需要资源ID作为参数传递,对吗?为什么不能实现您自己的一个方法类(称为ResourceFactory)返回一个Android创建的资源?很抱歉我的解释不充分。我更新了我的问题。我认为factory仍然无法获得有关注入目标字段的信息。是的,尽管您可以注入(比如)您编写的ResourceInjector,这可以反映整个类(ResourceInjector.injectActivity(this))和它的字段寻找您的注释。然后您可以在测试中使用假的或模拟的ResourceInjector。酷!请注意.annotatedWith(Named.class)
是一种不太受欢迎的Guice行为。如果我是你,我不会使用绑定注释来获取值。此外,我认为AtomicReference
在存在线程的情况下不会为你提供正确的语义,你需要ThreadLocal
class MyConsumer {
final Resource resource;
@Inject MyConsumer(Resource.Factory resourceFactory) {
int previouslyAnnotatedValue = 5;
this.resource = resourceFactory.createWithValue(previouslyAnnotatedValue);
}
}
import java.lang.reflect.{Constructor, Parameter}
import java.util.concurrent.atomic.AtomicReference
import javax.inject.{Inject, Named, Provider}
import com.google.inject.matcher.Matchers
import com.google.inject.spi.ProvisionListener.ProvisionInvocation
import com.google.inject.{AbstractModule, Binder, Guice}
import com.google.inject.spi.{DependencyAndSource, ProviderInstanceBinding, ProvisionListener}
import com.typesafe.config.ConfigFactory
import net.codingwell.scalaguice.InjectorExtensions._
import net.codingwell.scalaguice.ScalaModule
import scala.collection.JavaConverters._
object GuiceExperiments extends App {
val injector = Guice.createInjector(new MyModule())
val some = injector.instance[Some]
println(some)
some.go()
}
trait Some {
def go(): Unit
}
class Impl @Inject()(
@Named("a.a.a") hello: String,
@Named("a.a.b") bello: String,
@Named("a.b.a") kello: String
) extends Some {
override def go() = {
println(hello)
println(bello)
println(kello)
}
}
abstract class DynamicProvider[T >: Null](binder: Binder) extends Provider[T] {
private[this] val nextValue = new AtomicReference[T]
binder.bindListener(Matchers.any(), new ProvisionListener {
private[this] def tryProvide(target: DependencyAndSource): Unit = {
val dependency = target.getDependency
val injectionPoint = dependency.getInjectionPoint
val parameterIndex = dependency.getParameterIndex
injectionPoint.getMember match {
case constructor: Constructor[_] =>
val parameter = constructor.getParameters()(parameterIndex)
nextValue.set(getFor(parameter))
}
}
override def onProvision[V](provision: ProvisionInvocation[V]): Unit = {
provision.getBinding match {
case binding: ProviderInstanceBinding[_] if binding.getUserSuppliedProvider eq DynamicProvider.this =>
provision.getDependencyChain.asScala.lastOption.foreach(tryProvide)
case _ => ()
}
}
})
final override def get(): T = nextValue.getAndSet(null)
def getFor(parameter: Parameter): T
}
class MyModule extends AbstractModule with ScalaModule {
override def configure(): Unit = {
bind[Some].to[Impl]
bind[String].annotatedWith[Named].toProvider(new DynamicProvider[String](binder) {
override def getFor(parameter: Parameter): String = {
if (parameter.isAnnotationPresent(classOf[Named])) {
parameter.getAnnotation(classOf[Named]).value()
} else {
null
}
}
})
}
}