SharedPreferenceへのアクセスはUIスレッドから実行する必要がありますか?
-
09-10-2019 - |
質問
ジンジャーブレッドのリリースで、私は新しいAPIのいくつかを試していますが、そのうちの1つは strictmode.
警告の1つが目的であることに気付きました getSharedPreferences()
.
これは警告です:
StrictMode policy violation; ~duration=1949 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2
そして、それはaのために与えられています getSharedPreferences()
UIスレッドで呼び出します。
したほうがいい SharedPreferences
アクセスと変更は本当にUIスレッドから行われますか?
解決
あなたがすでにそれで遊んでいることをうれしく思います!
注意すべきこと: (怠惰な弾丸の形で)
- これがあなたの問題の最悪である場合、あなたのアプリはおそらく良い場所にあります。 :)書き込みは一般に読み取りよりも遅いので、commit()の代わりにsharedprefered $ editor.apply()を使用していることを確認してください。 Apply()はGBおよびASYNCで新しくなっています(ただし、ライフサイクルの移行に注意してください)。 Reflectionを使用して、Froyo以下でGB+およびcommit()でapply()およびcommit()を条件付きで呼び出すことができます。これを行う方法のサンプルコードを使用してブログ投稿をします。
ただし、読み込みについて...
ロードされると、共有予約はシングルトンとプロセス全体のキャッシュです。そのため、できるだけ早くロードして、必要になる前にメモリに入れることをお勧めします。 (SharedPreferences、Simple XMLファイルを使用している場合は小さいと仮定すると...)将来、一部のユーザーがボタンをクリックする将来はそれを誤りたくありません。
ただし、Context.GetSharedPreferences(...)を呼び出すときはいつでも、バッキングXMLファイルが変更されているかどうかを確認するため、とにかくUIイベント中にそれらの統計を回避する必要があります。統計は通常高速である(そしてしばしばキャッシュされた)必要がありますが、Yaffsは同時性の方法ではあまりありません(そして、多くのAndroidデバイスがYAFFSで実行されます...ドロイド、ネクサス1など)。 、他の飛行または保留中のディスク操作の後ろに立ち往生することを避けます。
したがって、おそらくonCreate()中に共有の表示をロードし、同じインスタンスを再利用して、統計を回避したいと思うでしょう。
ただし、OnCreate()中にとにかく設定が必要ない場合は、その読み込み時間がアプリの起動を不必要に停止しているため、一般的にFutureTaskのようなものを持っている方が良いですu003CSharedPreferences>.set()futureTaskサブクラスの値に新しいスレッドをキックオフするサブクラス。次に、FutureTaskを検索してくださいu003CSharedPreferences>必要なときはいつでもメンバーと.get()それ。私はこれをハニカムの舞台裏で透明にするつもりです。この分野でベストプラクティスを示すサンプルコードをリリースしようとします。
Android Developersブログでは、今後のStrictMode関連の主題に関する今後の投稿を確認してください。
他のヒント
共有設定にアクセスするには、フラッシュストレージから読み取られるため、かなり時間がかかります。たくさん読んでいますか?たぶん、SQLiteデータベースなど、別の形式を使用できます。
ただし、StrictModeを使用して見つけたすべてを修正しないでください。またはドキュメントを引用するには:
しかし、StrictModeが見つけたすべてのものを修正することを強いられないと感じないでください。特に、通常のアクティビティライフサイクル中にディスクアクセスの多くのケースが必要です。 StrictModeを使用して、偶然にしたことを見つけます。ただし、UIスレッドのネットワーク要求はほとんど常に問題です。
Bradの答えについての1つの微妙さ:oncreate()に共有監督をロードしたとしても、GetString()などが(バックグラウンドスレッド上)に共有ファイルの設定を読み取るまでブロックするため、おそらく背景スレッドで値を読み取る必要があります。
public String getString(String key, String defValue) {
synchronized (this) {
awaitLoadedLocked();
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
編集()も同じ方法でブロックされますが、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;
}
}
}
MainActivity(アプリケーションで最初に呼び出されるアクティビティ):
LocalPreference.getLocalPreferences(this);
説明された手順:
- メインアクティビティは、getLocalPreferences(this) - >これで好みを読み取り、アプリケーションクラスにフィルターオブジェクトを設定して返します。
- getLocalPreferences()を呼び出すと、アプリケーションのどこかで再び機能すると、アプリケーションクラスでははるかに高速なアプリケーションクラスで利用できないかどうかを確認します。
注:アプリケーションワイド変数がnullとは異なるかどうかを常に確認します、理由 - > http://www.developerphil.com/dont-store-data-in-application-object/
アプリケーションオブジェクトは永遠にメモリにとどまることはなく、殺されます。一般的な信念に反して、アプリはゼロから再起動することはありません。 Androidは、新しいアプリケーションオブジェクトを作成し、ユーザーが以前にあったアクティビティを開始し、最初にアプリケーションが決して殺されなかったという幻想を与えます。
nullをチェックしなかった場合、フィルターオブジェクトのgetmaxdistance()を呼び出すときにnullpointerをスローすることを許可します(アプリケーションオブジェクトがAndroidによってメモリからスワイプされた場合)