Android sharedPreferences.commit无法读取文件



我有一个广播接收器,它清除共享的首选项文件,然后提交。我的应用程序运行到ANR,因为清除工作,但由于某种原因,提交无法读取文件

广播接收器也超时。。

我无法理解堆栈跟踪的含义。有人能帮我了解这里发生了什么吗?有没有办法避免这种情况?

这是堆栈跟踪:

"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 obj=0x7599a000 self=0xb84a5e98
| sysTid=15259 nice=0 cgrp=bg_non_interactive sched=0/0 handle=0xb6f1d000
| state=S schedstat=( 137176743 6798788178 493 ) utm=4 stm=9 core=0 HZ=100
| stack=0xbe0d0000-0xbe0d2000 stackSize=8MB
| held mutexes=
kernel: (couldn't read /proc/self/task/15259/stack)
native: #00 pc 00012ab0  /system/lib/libc.so (syscall+28)
native: #01 pc 000a98af  /system/lib/libart.so (_ZN3art17ConditionVariable4WaitEPNS_6ThreadE+82)
native: #02 pc 001c1529  /system/lib/libart.so (_ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh+672)
native: #03 pc 000139eb  /system/lib/libjavacore.so (???)
native: #04 pc 00020dfd  /system/lib/libjavacore.so (???)
native: #05 pc 002859e3  /system/framework/arm/boot.oat (Java_libcore_io_Posix_open__Ljava_lang_String_2II+118)
at libcore.io.Posix.open(Native method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
at libcore.io.IoBridge.open(IoBridge.java:442)
at java.io.FileOutputStream.<init>(FileOutputStream.java:89)
at java.io.FileOutputStream.<init>(FileOutputStream.java:74)
at android.app.SharedPreferencesImpl.createFileOutputStream(SharedPreferencesImpl.java:578)
at android.app.SharedPreferencesImpl.writeToFile(SharedPreferencesImpl.java:631)
at android.app.SharedPreferencesImpl.access$900(SharedPreferencesImpl.java:53)
at android.app.SharedPreferencesImpl$2.run(SharedPreferencesImpl.java:532)
- locked <@addr=0x22d600f0> (a java.lang.Object)
at android.app.SharedPreferencesImpl.enqueueDiskWrite(SharedPreferencesImpl.java:551)
at android.app.SharedPreferencesImpl.access$100(SharedPreferencesImpl.java:53)
at android.app.SharedPreferencesImpl$EditorImpl.commit(SharedPreferencesImpl.java:473)

这是示例代码:

public class AppBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences mSharedPre = context.getSharedPreferences("sharedPrefFile", Context.MODE_PRIVATE);
SharedPreferences.Editor sharedPrefEditor = mSharedPre.edit();
sharedPrefEditor.clear();
sharedPrefEditor.commit();
}
}

这里发生的情况是,您正在主线程上加载一个文件,这花费了太长时间,并导致应用程序ANR。

为什么

代码中存在两个问题,可能会导致ANR。

当你第一次调用context.getSharedPreferences()时,Android会启动一个作业,读取底层的首选项文件(一个XML文件(并将所有数据加载到内存中。在进行此加载时,从SharedPreferences对象获取任何数据的所有调用都将被阻止,直到加载作业完成。这包括您在onReceive()中进行的对edit()的调用。

第二个问题是对commit()的调用。这将对SharedPreferences中的底层首选项文件执行同步写入,从而阻塞调用线程(在您的情况下,这也是主线程(。这也将导致ANR。

可能的解决方案

首先,我会将调用移动到更接近应用程序启动的位置,以加载您的偏好。一个好地方是Application.onCreate()。在此方法中,您应该只调用getSharedPreferences()only。你根本不想在这里阻塞主线程。这将在调用onReceive()之前为您的首选项提供加载时间。

其次,不要使用commit()。我建议使用apply()。这样可以确保数据立即存储在内存中,同时将数据异步写入底层首选项文件。然而,ANR仍然有机会,特别是因为当接收器完成onReceive()时(以及在其他情况下(,Android用于异步执行写入作业的队列会刷新到主线程上。我不会太担心这种情况,只是需要注意一些。

最后,我不建议使用grandcentrx/tray,因为它不再受支持,如果使用不当,可能会导致其他ANR。如果您的应用程序是单进程应用程序,请不要使用多进程解决方案。

每个接收程序总是在一个新进程中启动,但不同进程之间不支持共享首选项。因此,如果是your app < API Level 23,则可以使用标志Context.MODE_MULTI_PROCESS:

context.getSharedPreferences("mypreferences", Context.MODE_PRIVATE |Context.MODE_MULTI_PROCESS);

注意:由于API级别23是不推荐使用的标志Context.MODE_MULTI_PROCESS,因此应使用ContentProvider在进程之间共享属性。此库https://github.com/grandcentrix/tray可以提供帮助。基本上,它是一个具有一些附加功能的ContentProvider包装器。

相关内容

  • 没有找到相关文章

最新更新