StrictMode:创建 SharedPreference 时的 StrictModeDiskReadViolation

Posted

技术标签:

【中文标题】StrictMode:创建 SharedPreference 时的 StrictModeDiskReadViolation【英文标题】:StrictMode: StrictModeDiskReadViolation when creating SharedPreference 【发布时间】:2018-09-25 06:38:11 【问题描述】:

我有一个带有以下提供程序方法的匕首设置项目:

@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:策略=196671 违规=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) 在 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】:

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)
    

【讨论】:

先生,这是正确的答案。感谢您的启发。对于其他读者,除了StrictMode.allowThreadDiskReads(),我还必须执行StrictMode.allowThreadDiskWrites()

以上是关于StrictMode:创建 SharedPreference 时的 StrictModeDiskReadViolation的主要内容,如果未能解决你的问题,请参考以下文章

<React.StrictMode></React.StrictMode> 组件到底是做啥的?

StrictMode 策略违规:android.os.strictmode.NonSdkApiUsedViolation: Lcom/android/org/conscrypt/ConscryptEn

findDOMNode 在 StrictMode 中已弃用。 findDOMNode 被传递了一个 DraggableCore 的实例,该实例位于 StrictMode 内

转:StrictMode使用

严苛模式(StrictMode)

错误:StrictMode $ AndroidBlockGuardPolicy.onNetwork