#android #kotlin #kotlin-multiplatform #kotlin-native
#Android #kotlin #kotlin -мультиплатформенный #kotlin- родной
Вопрос:
В настоящее время я разрабатываю простой модуль KMM, который необходим Context
для выполнения некоторых операций. Я знаю о способах достижения этого с помощью расширения Application
класса и внедрения зависимостей. Что я пытаюсь сделать прямо сейчас — сделать этот модуль доступным из коробки без необходимости изменять manifest
или вводить вручную при запуске. Мне просто интересно, является ли плохой практикой делать что-то подобное:
@SuppressLint("StaticFieldLeak")
object SomeUtil {
private val context = Activity().applicationContext
}
Поскольку applicationContext
возвращает Context
для всего приложения, и мы инициализируем его один раз, будет ли утечка? Или есть какие-то другие моменты, чтобы не делать этого?
Может быть, есть какие-то другие возможности для получения контекста приложения из модуля? Я видел несколько примеров извлечения его из потоков, но, насколько я понимаю, это будет (или уже) устаревшим.
UPD: это вызывает ошибку. Activity()
кажется null
, да. Итак, есть идеи, как добиться этого без DI и «MyApplication»?
Ответ №1:
Ну, я бы начал с того, что это на самом деле не вопрос KMM. Это относится только к коду Android.
Насколько я знаю, нет, нет способа статически глобально получить доступ к контексту приложения без некоторых полу-хакерских решений. Это давняя проблема, которая на самом деле не имеет хорошего решения.
Crashlytics делает (делал?) Что-то странное, регистрируя ContentProvider, единственная цель которого — получить приложение и сделать его доступным. Предполагая, что вы публикуетесь как aar, он зарегистрирует ContentProvider для вас.
https://firebase.googleblog.com/2016/12/how-does-firebase-initialize-on-android.html
Я бы не рекомендовал этого делать. Я очень предпочитаю настраивать инициализацию контекста библиотеки самостоятельно, но вы можете попробовать маршрут ContentProvider.
Комментарии:
1. Просматривая веб-страницы, я также обнаружил это , что также похоже на то, чего магглы не должны делать. Так что я тоже смотрю в DI, что немного разочаровывает
2. «Ну, я бы начал с того, что это на самом деле не вопрос KMM». Как наличие разных аргументов для разных платформ зависит от Android и не связано с KMM?
Ответ №2:
Это распространенная проблема в библиотеках Android — как получить контекст приложения, не имея доступа к кодовой базе приложения? Вот почему вы часто инициализируете библиотеки с помощью чего-то вроде SharedPrefHelper.init(applicationContext)
в вашем Application.onCreate()
Поскольку общий код KMM является библиотекой, вы сталкиваетесь с аналогичной проблемой. Android app startup — это библиотека androidx, созданная для решения этой проблемы (а также для повышения производительности запуска).
Примерный пример (все в общем коде):
// In androidMain
class MySqlDelightInitialiser : Initializer<SqlDriver> {
override fun create(context: Context): SqlDriver {
val driver = createDriver(context)
MyLibraryObject.init(context, driver)
return driver
}
override fun dependencies(): List<Class<out Initializer<*>>> {
return emptyList()
}
}
// In androidMain/AndroidManifest
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.sql-delight-initialiser"
android:exported="false"
tools:node="merge"
tools:replace="android:authorities"
>
<meta-data
android:name="my.package.SqlDelightInitialiser"
android:value="androidx.startup"
/>
</provider>
</application>
Ответ №3:
Короткий ответ: введите его в конструктор или как параметр метода:
class SomeUtil(private val context: Context) {
....
}
object SomeUtil {
fun someMethod(context: Context) { .... }
}
Экземпляры контекста (а также Activity, Application, Service) создаются и уничтожаются Android Framework, и создание экземпляров вручную (или mocking), вероятно, будет работать во время компиляции, но они будут вызывать исключения во время выполнения