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 内