126

Gingerbreadのリリースに伴い、私はいくつかの新しいAPIを試してきましたが、そのうちの1つはStrictModeです。

警告の1つがのためのものであることに気づきましたgetSharedPreferences()

これは警告です:

StrictMode policy violation; ~duration=1949 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2

getSharedPreferences()そしてそれはUIスレッドで行われている呼び出しのために与えられています。

SharedPreferencesアクセスと変更は本当にUIスレッドから行う必要がありますか?

4

6 に答える 6

190

すでに遊んでくれてうれしいです!

注意すべき点:( 怠惰な弾丸の形で)

  • これが最悪の問題である場合、アプリはおそらく良い場所にあります。:)ただし、書き込みは一般に読み取りよりも遅いため、commit()の代わりにSharedPreferenced $ Editor.apply()を使用していることを確認してください。apply()はGBと非同期の新機能です(ただし、常に安全で、ライフサイクルの移行に注意してください)。リフレクションを使用して、GB +ではapply()を、Froyo以下ではcommit()を条件付きで呼び出すことができます。これを行う方法のサンプルコードを含むブログ投稿を行います。

ただし、読み込みに関しては...

  • 一度ロードされると、SharedPreferencesはシングルトンになり、プロセス全体にキャッシュされます。したがって、必要になる前にメモリに保存できるように、できるだけ早くロードする必要があります。(SharedPreferences、単純なXMLファイルを使用している場合のように小さいと仮定します...)将来、一部のユーザーがボタンをクリックしたときに障害が発生したくない場合。

  • ただし、context.getSharedPreferences(...)を呼び出すと、バッキングXMLファイルが変更されたかどうかを確認するために統計情報が送信されるため、UIイベント中にこれらの統計情報を回避する必要があります。統計は通常高速である必要があります(そして多くの場合キャッシュされます)が、yaffsは同時実行性の点であまりありません(そして多くのAndroidデバイスはyaffsで実行されます... Droid、Nexus Oneなど)ディスクを避ける場合、他の実行中または保留中のディスク操作の背後でスタックすることを回避します。

  • したがって、onCreate()中にSharedPreferencesをロードし、統計を避けて同じインスタンスを再利用することをお勧めします。

  • ただし、onCreate()中に設定が必要ない場合は、読み込み時間が不必要にアプリの起動を停止させるため、一般的には、FutureTask<SharedPreferences>サブクラスのようなものを使用して新しいスレッドを.setに開始することをお勧めします。 ()FutureTaskサブクラスの値。次に、FutureTask <SharedPreferences>のメンバーを必要なときにルックアップし、.get()します。私はこれをHoneycombの舞台裏で透過的に無料にする予定です。この分野のベストプラクティスを示すサンプルコードをリリースしてみます。

今後数週間のStrictMode関連のテーマに関する今後の投稿については、AndroidDevelopersブログを確認してください。

于 2010-12-06T23:07:54.387 に答える
5

共有設定へのアクセスは、フラッシュストレージから読み取られるため、かなり時間がかかる場合があります。たくさん読んでいますか?たぶん、SQLiteデータベースなどの別の形式を使用できます。

ただし、StrictModeを使用して見つけたものをすべて修正しないでください。または、ドキュメントを引用するには:

ただし、StrictModeが検出したすべてを修正する必要があるとは思わないでください。特に、ディスクアクセスの多くのケースは、通常のアクティビティライフサイクル中に必要になることがよくあります。StrictModeを使用して、誤って行ったことを見つけます。ただし、UIスレッドでのネットワーク要求は、ほとんどの場合問題になります。

于 2010-12-06T21:54:39.000 に答える
5

Bradの答えに関する1つの微妙な点:onCreate()でSharedPreferencesをロードした場合でも、getString()などが(バックグラウンドスレッドで)終了時に共有ファイル設定を読み取るまでブロックするため、おそらくバックグラウンドスレッドで値を読み取る必要があります。

public String getString(String key, String defValue) {
    synchronized (this) {
        awaitLoadedLocked();
        String v = (String)mMap.get(key);
        return v != null ? v : defValue;
    }
}

edit()も同じ方法でブロックしますが、apply()はフォアグラウンドスレッドでは安全であるように見えます。

(ところで、これをここに置いて申し訳ありません。これをブラッドの答えへのコメントとして入れていただろうが、私は参加したばかりで、そうするのに十分な評判がありません。)

于 2014-11-11T01:40:17.287 に答える
1

これは古い質問ですが、私のアプローチを共有したいと思います。私は長い読書時間を持っていて、共有設定とグローバルアプリケーションクラスの組み合わせを使用しました:

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);

説明した手順:

  1. 主なアクティビティはgetLocalPreferences(this)->を呼び出します。これにより、設定が読み取られ、アプリケーションクラスにフィルターオブジェクトが設定されて返されます。
  2. getLocalPreferences()関数をアプリケーションの別の場所で再度呼び出すと、最初に、はるかに高速なアプリケーションクラスで使用できないかどうかがチェックされます。

注:アプリケーション全体の変数がNULLと異なるかどうかを常に確認してください。理由-> http://www.developerphil.com/dont-store-data-in-the-application-object/

アプリケーションオブジェクトは永久にメモリに残ることはなく、強制終了されます。一般に信じられていることとは異なり、アプリは最初から再起動されません。Androidは、新しいアプリケーションオブジェクトを作成し、ユーザーが以前にいた場所でアクティビティを開始して、アプリケーションが最初から強制終了されなかったという錯覚を与えます。

nullをチェックしなかった場合、たとえばフィルターオブジェクトでgetMaxDistance()を呼び出すときにnullポインターをスローできるようにします(アプリケーションオブジェクトがAndroidによってメモリからスワイプされた場合)

于 2015-05-20T12:20:21.007 に答える
0

SharedPreferencesクラスは、ディスク上のXMLファイル内でいくつかの読み取りと書き込みを行うため、他のIO操作と同様にブロックする可能性があります。SharedPreferencesに現在保存されているデータの量は、API呼び出しによって消費される時間とリソースに影響します。最小限のデータ量の場合、データを取得/配置するのに数ミリ秒(場合によっては1ミリ秒未満)の問題があります。ただし、専門家の観点からは、API呼び出しをバックグラウンドで実行してパフォーマンスを向上させることが重要になる可能性があります。非同期のSharedPreferencesについては、データムライブラリを確認することをお勧めします。

于 2020-08-10T08:02:55.810 に答える
0

バックグラウンドスレッドからそれらを読み取る理由はわかりません。しかし、それを書くために私はそうします。起動時に共有設定ファイルがメモリに読み込まれるため、アクセスは高速ですが、書き込みには少し時間がかかる場合があるため、writeasyncの適用を使用できます。これが、共有設定のcommitメソッドとapplyメソッドの違いです。

于 2020-08-26T11:01:10.290 に答える