StrictMode:创建SharedPreference时的StrictModeDiskReadViolation

azi*_*ian 1 android disk-io kotlin android-sharedpreferences android-strictmode

我有一个带有匕首设置的项目,具有以下提供者方法:

@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

}
Run Code Online (Sandbox Code Playgroud)

这是来自应用程序的代码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()
}
Run Code Online (Sandbox Code Playgroud)

在API 27模拟器上运行项目会导致以下行为:

使用以下日志:

D/StrictMode:StrictMode策略违规; 〜duration = 275 ms:android.os.StrictMode $ StrictModeDiskReadViolation:policy = 196671 violation = 2 at android.os.StrictMode $ AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1440)at java.io.UnixFileSystem.checkAccess(UnixFileSystem.java: 251)在java.io.File.exists(File.java:807)的android.app.ContextImpl.getDataDir(ContextImpl.java:2197)在Android上的android.app.ContextImpl.getPreferencesDir(ContextImpl.java:517).在Android.pretent.PreferenceManager.getDefaultSharedPreferences的android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:167)的android.app.ContextImpl.getSharedPreferences(ContextImpl.java:368)上的app.ContextImpl.getSharedPreferencesPath(ContextImpl.java:714) (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());
}
Run Code Online (Sandbox Code Playgroud)

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

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

我不想因为这个问题而关闭读/写StrictMode规则.

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

Kis*_*kae 7

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

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

val oldPolicy = StrictMode.allowThreadDiskReads()
try {
    // Do reads here
} finally {
    StrictMode.setThreadPolicy(oldPolicy)
}
Run Code Online (Sandbox Code Playgroud)

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

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