Dependencies 如何与在GUI中使用注释值的提供程序绑定?

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

是否有任何方法可以绑定在GoogleGuice中解释目标注释值的提供者

例如:

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
        }
      }
    })

  }

}