StrictMode: StrictModeDiskReadViolation при создании SharedPreference
У меня есть проект с настройкой кинжала со следующим методом провайдера:
@Module(...)
abstract class AppModule {
@Module
companion object {
...
@Provides
@Singleton
@JvmStatic
fun provideSharedPreferences(@AppContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
}
@Binds
@AppContext
@Singleton
abstract fun provideAppContext(application: Application): Context
}
А вот код из приложения onCreate()
:
override fun onCreate() {
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDialog()
.build())
StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
Timber.plant(Timber.DebugTree())
}
...
super.onCreate()
}
Запуск проекта на эмуляторе API 27 приводит к следующему поведению:
Со следующими журналами:
D / StrictMode: нарушение политики StrictMode; ~duration=275 мс: android.os.StrictMode$StrictModeDiskReadViolation: policy=196671 нарушение = 2 на android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1440) в java.io.UnixFileSystem.cheavaFileSystem.checkAccessSystem.checkAccess (251) в java.io.File.exists(File.java:807) в android.app.ContextImpl.getDataDir(ContextImpl.java:2197) в android.app.ContextImpl.getPreferencesDir(ContextImpl.java:517) в Android. Приложение (PreferenceManager.java:526) в com.some.package.di.module.AppModule$Companion.provideSharedPreferences(AppModule.kt:112) ...
Что это значит? res.exists()
читает с диска:
if (!res.exists() && android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
Log.wtf(TAG, "Data directory doesn't exist for package " + getPackageName(),
new Throwable());
}
И потому что это происходит в потоке пользовательского интерфейса - StrictModeDiskReadViolation
Результаты.
На самом деле, не существует API для исключения некоторого фрагмента кода (например, по имени пакета) из конфигурации StrictMode. Практически я в порядке, чтобы уйти SharedPreferences
связанные вещи для чтения с диска в потоке пользовательского интерфейса.
Я не хочу отключать чтение / запись правила StrictMode из-за этой проблемы.
Вопрос
Как правильно изящно оправиться от этого сценария?
1 ответ
На самом деле, не существует API для исключения некоторого фрагмента кода (например, по имени пакета) из конфигурации StrictMode. На практике я могу оставить материал, связанный с SharedPreferences, для чтения с диска в потоке пользовательского интерфейса.
Это существует. StrictMode.allowThreadDiskReads()
изменяет разрешения для чтения и возвращает старые ThreadPolicy
поэтому его можно сбросить после завершения чтения. Затем его можно использовать вместе с настройкой "try-finally", чтобы разрешить чтение для одного действия.
val oldPolicy = StrictMode.allowThreadDiskReads()
try {
// Do reads here
} finally {
StrictMode.setThreadPolicy(oldPolicy)
}
Вы можете создать функцию kotlin, которая обрабатывает восстановление с помощью лямбды:
fun <T> allowReads(block: () -> T): T {
val oldPolicy = StrictMode.allowThreadDiskReads()
try {
return block()
} finally {
StrictMode.setThreadPolicy(oldPolicy)
}
}