Ошибка Kotlin: Dagger не поддерживает внедрение в приватные поля

Я использую в Kotlin активность ViewPager, и я хочу в Kotlin Fragment использовать инъекцию кинжала. У меня ошибка: Dagger не поддерживает инъекцию в приватные поля. В Java Fragment работают инъекции кинжала. Почему я не могу ввести кинжал в Kotlin Faragment?

в моей деятельности kotlin

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 build

12 ответов

Решение

Случайно я наткнулся на свой собственный ответ и должен признаться, что на самом деле он не работает (по крайней мере, для моего варианта использования). Пожалуйста, примите во внимание ответ Авилио, который также помог мне: заменить internal с lateinit,


Старый ответ

Удалить internal модификатор. Для доступа к аннотированному полю Dagger необходим как минимум частный доступ к пакету. В котлине internal Модификатор не является заменой для модификатора закрытого доступа Java.

Подробное объяснение различий между модификаторами в Java и Kotlin см. В эпизоде фрагментированного подкаста № 101 - "Изучение Kotlin - модификаторы видимости, внутренний модификатор, модули", а также в официальных документах.

Вы ошиблись здесь:

    @Inject
internal var mSharedPreferences: SharedPreferences? = null

Похоже, вы добавили @Inject аннотация к KotlinFragment учебный класс

Пожалуйста, измените это на это, и это будет работать:

var mSharedPreferences: SharedPreferences? = null
        @Inject set

Вот ссылка на документацию: https://kotlinlang.org/docs/reference/annotations.html

Как просто вы можете сделать это, измените эту строку

@Inject
internal var mSharedPreferences: SharedPreferences? = null

к

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

эта работа как шарм в моем случае.

У меня была такая же ошибка, даже после удаления внутреннего ключевого слова. Поэтому я заменил внутренний на lateinit, и это сработало.

@Inject
lateinit var mSharedPreferences: SharedPreferences

Кроме того, это сработало и для поздней инициализации переменной

Я последовал приведенному выше совету не делать поле внутренним. Но этого было недостаточно. Kapt все еще преобразует переменную в частную во время компиляции.

Мне пришлось добавить @JvmField аннотацию, чтобы она работала лучше.

Ответ, который я нашел, был здесь: https://discuss.kotlinlang.org/t/kapt-converting-public-fields-to-private-during-compilation/11757

      @Inject
internal var mSharedPreferences: SharedPreferences? = null

Просто изменил это на

      @Inject
lateinit var mSharedPreferences: SharedPreferences

PS Вы не можете использовать lateinit с нулевыми значениями.

Удалить internal модификатор. И я также должен был объявить lateinit и удалите Необязательный.

В моем случае я изменил

      @Inject
var locationDBWrapper: LocationDBWrapper? = null

к

      @Inject
lateinit var locationDBWrapper: LocationDBWrapper

Проблема решена

Вы определили fun inject(fragment: KotlinFragment) в вашем ApplicationComponent? Потому что, похоже, ваше сообщение об ошибке говорит именно об этом.

РЕДАКТИРОВАТЬ: возможно, вы не предоставили SharedPreferences в вашем модуле вот так:

@Module
public class AndroidModule {
    private final TimrApplication application;

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

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

После обновления до Android Studio 3.5 большинство ответов не работают. Консолидированное решение:

1. Если вы хотите использовать:

      @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

Вы не можете сделать внедренные вары частными, но вы можете сделать их защищенными, что фактически то же самое в последнем классе (а в Kotlin классы являются окончательными по умолчанию, если вы не используете модификатор «open»). Также используйте модификатор lateinit, как уже было сказано.

      @Inject
protected lateinit var mSharedPreferences: SharedPreferences

Если ваш класс не открыт, в Android Studio может появиться предупреждение о том, что «защищенная» видимость фактически является «частной» в последнем классе »- вы можете просто подавить это с помощью:

      @Suppress("ProtectedInFinal")
Другие вопросы по тегам