Kotlin Error: Dagger does not support injection into private fields

Kotlin Error: Dagger does not support injection into private fields

我在 kotlin 中使用 activity ViewPager,我想在 Kotlin Fragment 中使用匕首注入。我有错误:Dagger 不支持注入私有字段。 在Java Fragment中匕首注入工作。 为什么我不能在 kotlin faragment 中注入匕首?

在我的科特林中 activity

mPagerAdapter = object : FragmentPagerAdapter(supportFragmentManager) {

        private val mFragments = arrayOf(KotlinFragment(), JavaFragment())
        private val mFragmentNames = arrayOf(getString(R.string.cashdocuments), getString(R.string.action_absmysql))

        override fun getItem(position: Int): Fragment {
            return mFragments[position]
        }

        override fun getCount(): Int {
            return mFragments.size
        }

        override fun getPageTitle(position: Int): CharSequence {
            return mFragmentNames[position]
        }
    }

我的科特林片段

class KotlinFragment : Fragment()  {


@Inject
internal var mSharedPreferences: SharedPreferences? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    (activity.application as SamfantozziApp).dgaeacomponent().inject(this)

}

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    super.onCreateView(inflater, container, savedInstanceState)
    val rootView = inflater!!.inflate(R.layout.activity_absserver, container, false)

    return rootView
}

}

消息gradle构建

我偶然发现了自己的答案,不得不承认,实际上它不起作用(至少对于我的用例而言)。请考虑对我也有用的 :将 internal 替换为 lateinit.


旧答案

删除 internal 修饰符。 Dagger 至少需要包私有访问权限才能访问带注释的字段。在 Kotlin 中,internal 修饰符 而不是 替代 Java 的包私有访问修饰符。

有关 Java 和 Kotlin 中修饰符之间差异的详细说明,请参阅 Fragmented podcast 的 episode #101 - "Learning Kotlin – visibility modifiers, internal modifier, modules", as well as the official docs

你在ApplicationComponent中定义了fun inject(fragment: KotlinFragment)了吗?因为看起来你的错误信息就是这么说的。

编辑:也许您没有像这样在您的模块中提供 SharedPreferences

@Module
public class AndroidModule {
    private final TimrApplication application;

    public AndroidModule(TimrApplication application) {
        this.application = application;
    }

    @Provides
    SharedPreferences provideSharedPreferences(){
        return PreferenceManager.getDefaultSharedPreferences(application);
    }
}

你这里有误:

    @Inject
internal var mSharedPreferences: SharedPreferences? = null

您似乎在 KotlinFragment class

中添加了 @Inject 注释

请改成这样,它会起作用:

var mSharedPreferences: SharedPreferences? = null
        @Inject set

这是文档的 link:https://kotlinlang.org/docs/reference/annotations.html

即使删除了内部关键字,我也遇到了同样的错误。所以我用 lateinit 替换了 internal 并且它起作用了。

删除 internal 修饰符。而且我还必须声明 lateinit 并删除 Optional。

很简单,你可以这样做,改变这一行

@Inject
internal var mSharedPreferences: SharedPreferences? = null

@set:Inject
internal var mSharedPreferences: SharedPreferences? = null

这对我来说很有魅力。

@Inject
lateinit var mSharedPreferences: SharedPreferences

此外,这对我也适用于后期初始化变量

我遵循了上面的建议,没有将字段设为内部。但是,这还不够。 Kapt 在编译期间仍然将 var 转换为 private。

我不得不添加 @JvmField 注释以使其表现更好。

我找到的答案在这里: https://discuss.kotlinlang.org/t/kapt-converting-public-fields-to-private-during-compilation/11757

在我的例子中,我改变了

@Inject
var locationDBWrapper: LocationDBWrapper? = null

@Inject
lateinit var locationDBWrapper: LocationDBWrapper

问题已解决

您不能将注入的变量设为私有,但可以将它们设为受保护,这在最终 class 中实际上是相同的(在 Kotlin 中 classes 默认是最终的,除非您使用“打开”修饰符)。另外,像已经说过的那样使用 lateinit 修饰符。

@Inject
protected lateinit var mSharedPreferences: SharedPreferences

如果您的 class 未打开,这可能会在 Android Studio 中产生警告,提示“'protected' 可见性在最终 class 中有效 'private' ]" - 你可以通过以下方式抑制它:

@Suppress("ProtectedInFinal")

更新到AndroidStudio 3.5后,大部分答案都不起作用。综合解决方案是:

1.如果你想使用 lateinit:

@Inject lateinit var mSharedPreferences: SharedPreferences

2。如果你不想使用 lateinit:

var mSharedPreferences: SharedPreferences? = null
    @Inject set(value) {
       field = value
}

@Inject
@JvmField
var mSharedPreferences: SharedPreferences

注意:这些方法不再有效。您收到错误 not a valid name: <set-?>Provide

@set:Inject
var mSharedPreferences: SharedPreferences? = null
var mSharedPreferences: SharedPreferences? = null 
    @Inject set
@Inject
internal var mSharedPreferences: SharedPreferences? = null

只需将其更改为

@Inject
lateinit var mSharedPreferences: SharedPreferences

P.S。您不能将 lateinit 与可空值一起使用。