应该从UI线程中完成访问共享流程吗?
-
09-10-2019 - |
题
随着姜饼的发布,我一直在尝试一些新API,其中之一是 Strictmode.
我注意到其中一个警告是 getSharedPreferences()
.
这是警告:
StrictMode policy violation; ~duration=1949 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2
它被给予了 getSharedPreferences()
在UI线程上呼叫。
应该 SharedPreferences
访问和更改真的是从UI线程中进行的吗?
解决方案
我很高兴您已经玩了!
有些事情要注意: (以懒惰的子弹形式)
- 如果这是您最糟糕的问题,那么您的应用程序可能处于一个很好的位置。 :)写字通常比读取慢,因此请确保您使用的是共享Predected $ editor.apply()而不是commit()。 appl()在GB和异步中是新的(但始终安全,要小心生命周期过渡)。您可以使用反射来有条件地调用froyo或以下的gb+和commit()上的apply()。我将使用一个博客文章,其中包含有关如何执行此操作的示例代码。
关于加载,但是...
加载后,共享流程是单元子和范围内的缓存。因此,您想尽早将其加载,以便在需要之前将其放在内存中。 (假设它很小,就像您使用共享Preferences一样,一个简单的XML文件...)您不想在将来的时间内对其进行错误的错误,某些用户单击一个按钮。
但是,每当您调用context.getSharedPreferences(...)时,backing XML文件是统计数据以查看是否已更改的,因此您仍然需要在UI事件期间避免使用这些统计信息。统计数据通常应该是快速(并且经常被缓存),但是Yaffs并没有太多的并发方式(并且许多Android设备在Yaffs上运行... Droid,Nexus One等),因此,如果您避免使用磁盘,您避免被困在其他机上或待处理的磁盘操作后面。
因此,您可能希望在otCreate()期间加载共享流量,并重复使用相同的实例,避免使用该统计数据。
但是,如果您在ongreate()期间不需要您的偏好u003CSharedPreferences>子类启动一个新线程为.set()FutureTask子类的值。然后查找您的履约u003CSharedPreferences>每当您需要它和.get()IT时。我计划透明地在Honeycomb的幕后自由。我将尝试发布一些在该领域显示最佳实践的示例代码。
在接下来的一周中查看Android开发人员博客即将发布的有关严格模块相关主题的帖子。
其他提示
访问共享首选项可能需要花费很多时间,因为它们是从Flash存储中读取的。你读了很多吗?也许您可以使用其他格式,例如SQLite数据库。
但是不要使用StrictMode修复您发现的所有内容。或引用文档:
但是,不要被迫修复严格模式找到的所有内容。特别是,在正常活动生命周期期间,通常需要许多磁盘访问情况。使用Strictmode查找您偶然做的事情。但是,UI线程上的网络请求几乎总是一个问题。
关于Brad的答案的一个微妙之处:即使您在onCreate()中加载了共享preference,也可能仍然应该在背景线程上读取值,因为getString()等,直到读取饰面中的共享文件偏好(在背景线程上):
public String getString(String key, String defValue) {
synchronized (this) {
awaitLoadedLocked();
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
edit()也以相同的方式阻挡,尽管apply()在前景线上似乎是安全的。
(顺便说一句,很抱歉将其放在这里。我会把它作为对布拉德的回答的评论,但我只是加入了,没有足够的声誉来做到这一点。)
我知道这是一个古老的问题,但我想分享我的方法。我有很长的阅读时间,并结合了共同的偏好和全球应用程序类:
ApplicationClass:
public class ApplicationClass extends Application {
private LocalPreference.Filter filter;
public LocalPreference.Filter getFilter() {
return filter;
}
public void setFilter(LocalPreference.Filter filter) {
this.filter = filter;
}
}
LocalPreference:
public class LocalPreference {
public static void saveLocalPreferences(Activity activity, int maxDistance, int minAge,
int maxAge, boolean showMale, boolean showFemale) {
Filter filter = new Filter();
filter.setMaxDistance(maxDistance);
filter.setMinAge(minAge);
filter.setMaxAge(maxAge);
filter.setShowMale(showMale);
filter.setShowFemale(showFemale);
BabysitApplication babysitApplication = (BabysitApplication) activity.getApplication();
babysitApplication.setFilter(filter);
SecurePreferences securePreferences = new SecurePreferences(activity.getApplicationContext());
securePreferences.edit().putInt(Preference.FILER_MAX_DISTANCE.toString(), maxDistance).apply();
securePreferences.edit().putInt(Preference.FILER_MIN_AGE.toString(), minAge).apply();
securePreferences.edit().putInt(Preference.FILER_MAX_AGE.toString(), maxAge).apply();
securePreferences.edit().putBoolean(Preference.FILER_SHOW_MALE.toString(), showMale).apply();
securePreferences.edit().putBoolean(Preference.FILER_SHOW_FEMALE.toString(), showFemale).apply();
}
public static Filter getLocalPreferences(Activity activity) {
BabysitApplication babysitApplication = (BabysitApplication) activity.getApplication();
Filter applicationFilter = babysitApplication.getFilter();
if (applicationFilter != null) {
return applicationFilter;
} else {
Filter filter = new Filter();
SecurePreferences securePreferences = new SecurePreferences(activity.getApplicationContext());
filter.setMaxDistance(securePreferences.getInt(Preference.FILER_MAX_DISTANCE.toString(), 20));
filter.setMinAge(securePreferences.getInt(Preference.FILER_MIN_AGE.toString(), 15));
filter.setMaxAge(securePreferences.getInt(Preference.FILER_MAX_AGE.toString(), 50));
filter.setShowMale(securePreferences.getBoolean(Preference.FILER_SHOW_MALE.toString(), true));
filter.setShowFemale(securePreferences.getBoolean(Preference.FILER_SHOW_FEMALE.toString(), true));
babysitApplication.setFilter(filter);
return filter;
}
}
public static class Filter {
private int maxDistance;
private int minAge;
private int maxAge;
private boolean showMale;
private boolean showFemale;
public int getMaxDistance() {
return maxDistance;
}
public void setMaxDistance(int maxDistance) {
this.maxDistance = maxDistance;
}
public int getMinAge() {
return minAge;
}
public void setMinAge(int minAge) {
this.minAge = minAge;
}
public int getMaxAge() {
return maxAge;
}
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}
public boolean isShowMale() {
return showMale;
}
public void setShowMale(boolean showMale) {
this.showMale = showMale;
}
public boolean isShowFemale() {
return showFemale;
}
public void setShowFemale(boolean showFemale) {
this.showFemale = showFemale;
}
}
}
Main Activity(在您的应用程序中首先被调用的活动):
LocalPreference.getLocalPreferences(this);
说明的步骤:
- 主活动调用getLocalPreferences(this) - >这将读取您的首选项,在应用程序类中设置过滤器对象并将其返回。
- 当您再次调用getLocalPreferences()函数时,该应用程序中的其他位置会首先检查应用程序类中是否不可用的速度要快得多。
注意:始终检查应用程序宽变量是否不同于null,原因 - > http://www.developererphil.com/dont-store-data-in-the-application-object/
应用对象不会永远留在记忆中,它将被杀死。与普遍的看法相反,该应用不会从头开始重新启动。 Android将创建一个新的应用程序对象,并启动用户以前的活动,以使该应用程序首先从未被杀死。
如果我不检查null,我将允许在滤波器对象上拨打nullpointer(例如getMaxDistance()时(如果Android从内存中刷动了应用程序对象)