StrictMode:StrictModeDiskReadViolation创建SharedPreference时

时间:2018-04-15 12:14:30

标签: android kotlin android-sharedpreferences disk-io android-strictmode

我有一个带有dagger设置的项目,使用以下提供程序方法:

@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 ms:android.os.StrictMode $ StrictModeDiskReadViolation:policy = 196671 violation = 2           在android.os.StrictMode $ AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1440)           在java.io.UnixFileSystem.checkAccess(UnixFileSystem.java:251)           在java.io.File.exists(File.java:807)           在android.app.ContextImpl.getDataDir(ContextImpl.java:2197)           在android.app.ContextImpl.getPreferencesDir(ContextImpl.java:517)           在android.app.ContextImpl.getSharedPreferencesPath(ContextImpl.java:714)           在android.app.ContextImpl.getSharedPreferences(ContextImpl.java:368)           在android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:167)           在android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:526)           at com.some.package.di.module.AppModule $ Companion.provideSharedPreferences(AppModule.kt:112)           ...

这意味着,following 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());
}

因为这会在UI线程上发生 - StrictModeDiskReadViolation结果。

Afaik,不存在用于从StrictMode配置中排除一些代码块(例如,通过包名称)的API。实际上,我可以将SharedPreferences相关内容留在UI线程上从磁盘读取。

由于这个问题,我不想关闭读/写StrictMode规则。

问题

从这种情况中正常恢复的正确方法是什么?

1 个答案:

答案 0 :(得分:5)

  

Afaik,不存在用于从StrictMode配置中排除一些代码块(例如,通过包名称)的API。实际上,我可以将与SharedPreferences相关的东西留在UI线程上从磁盘读取。

确实存在。 StrictMode.allowThreadDiskReads()更改权限以允许读取并返回旧ThreadPolicy,以便在读取完成后重置它。然后,这可以与“try-finally”设置一起使用,以允许读取单个操作。

val oldPolicy = StrictMode.allowThreadDiskReads()
try {
    // Do reads here
} finally {
    StrictMode.setThreadPolicy(oldPolicy)
}

您可以使用lambda创建一个kotlin函数来处理恢复:

fun <T> allowReads(block: () -> T): T {
    val oldPolicy = StrictMode.allowThreadDiskReads()
    try {
        return block()
    } finally {
        StrictMode.setThreadPolicy(oldPolicy)
    }
}