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)
    }
}
Другие вопросы по тегам