74

私はonSharedPreferenceChanged私の主な活動に実装しました。

メインアクティビティで設定を変更すると、イベントが発生します。

設定画面で設定を変更した場合(PreferenceActivity)設定が変更されてもイベントは発生しません(これは、sharedPreferencesへの個別のアクティビティと個別の参照であるためですか?)

この状況を克服するために私がどのように取り組むべきかについて誰かがアドバイスを持っていますか?

ありがとう!

編集1:設定アクティビティにイベントハンドラーを追加しようとしましたが、起動しません。次のメソッドは、設定アクティビティのonCreate中に呼び出されます。値を変更しても、メッセージは出力されません(msg()のラッパーですLog.d)。

private void registerChangeListener () {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);

    sp.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener () {
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            msg (" ***** Shared Preference Update ***** ");
            Intent i = new Intent();
            i.putExtra("KEY", key);
            i.setAction("com.gtosoft.dash.settingschanged");

            sendBroadcast(i);

            // TODO: fire off the event
        }
    });
}
4

9 に答える 9

146

OnSharedPreferenceChangeListener匿名クラスを使用する場合、はガベージコレクションを取得します。

この問題を解決するには、次のコードを使用しPreferenceActivityて変更リスナーを登録および登録解除します。

public class MyActivity extends PreferenceActivity implements
    OnSharedPreferenceChangeListener {

@Override
protected void onResume() {
    super.onResume();
    // Set up a listener whenever a key changes
    getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
}

@Override
protected void onPause() {
    super.onPause();
    // Unregister the listener whenever a key changes
    getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
}

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,String key) 
{
  // do stuff
}

さらに、リスナーは実際の値が変更された場合にのみ呼び出されることに注意してください。同じ値を再度設定しても、リスナーは起動しません。

SharedPreferences.onSharedPreferenceChangeListenerが一貫して呼び出されていないも参照してください

于 2010-09-26T21:26:33.107 に答える
18

これは、ガベージコレクターが原因で発生します。その動作は1回だけです。その後、参照はガベージとして収集されます。したがって、リスナーのインスタンスフィールドを作成します。

private OnSharedPreferenceChangeListener listner;

listner = new SharedPreferences.OnSharedPreferenceChangeListener() {        
        @Override
        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
            //implementation goes here
        }
    };
    prefs.registerOnSharedPreferenceChangeListener(listner);
于 2012-09-05T08:47:34.610 に答える
8

true他の多くの人と同じように、ブール値をからfalse、またはその逆に変更してもリスナーが解雇されないため、ここに到着しました。

多くの読書、リファクタリング、切り替えcontexts/inner classes/privates/static/などを行った後、私は自分の(愚かな)エラーに気づきました:

は、何かが変更された場合にのみ呼び出されonSharedPreferenceChangedますそれだけ。これまで。

テスト中、私はいつも同じボタンをクリックするのがとても馬鹿でした。そのため、常に同じブール値を設定に割り当てていたので、変更されることはありませんでした。

これが誰かに役立つことを願っています!!

于 2013-10-10T13:00:33.700 に答える
3

この問題を回避するもう1つの方法は、アクティビティをリスナークラスにすることです。固有の名前を持つオーバーライドメソッドは1つしかないため、これを行うことができます。

public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sharedPreferences.registerOnSharedPreferenceChangeListener(this);
        ...
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
    {
        ...
    }
} 
于 2015-07-18T22:44:25.283 に答える
1

PreferenceActivityの設定変更をリッスンしているMainActivityについての元の質問に注意してください。次に、質問者は「EDIT1」を追加し、質問をPreferenceActivity自体で聞くように変更しました。それは前者よりも簡単で、すべての答えが想定しているようです。しかし、それでも前者のシナリオが必要な場合はどうでしょうか。

それも機能しますが、リスナーの登録と登録解除にOnResume()とOnPause()を使用しないでください。これを行うと、ユーザーがPreferenceActivityを使用するときにMainActivityを離れるため、リスナーは無効になります(これは、考えてみると理にかなっています)。したがって、機能しますが、ユーザーが使用していない場合でも、MainActivityはバックグラウンドでリッスンします。一種の資源の浪費ですね。したがって、機能しているように見える別の解決策があります。OnResume()にメソッドを追加するだけで、すべての設定を再読み取りできます。そうすれば、ユーザーがPreferenceActivityで設定の編集を終了したときに、ユーザーが戻ったときにMainActivityがそれらを取得し、リスナーはまったく必要ありません

このアプローチに問題がある場合は、誰かに知らせてください。

于 2016-07-15T04:30:20.047 に答える
0

onSharedPreferenceChanged好みが変わる可能性のある残りのアクティビティにを追加してみませんか?

于 2010-09-26T17:51:46.877 に答える
0

ガベージコレクターはそれを消去します...代わりにアプリケーションコンテキストの使用を検討する必要があります...またはアプリの起動時にコードを追加するだけです...そしてアプリケーションコンテキストでリスナーを追加します...

于 2016-11-14T20:22:24.623 に答える
0

PreferencesChangeListenerをAndroidAppクラスインスタンス内に保持することを検討してください。アプリ内に参照を保存することはクリーンなソリューションではありませんが、GCがリスナーをガベージコレクションするのを防ぎ、DB変更の更新を受信できるはずです。プリファレンスマネージャーはリスナーへの強力な参照を保存しないことに注意してください。WeakHashMap

/**
 * Main application class
 */
class MyApp : Application(), KoinComponent {

    var preferenceManager: SharedPreferences? = null
    var prefChangeListener: MySharedPrefChangeListener? = null

    override fun onCreate() {
        super.onCreate()

        preferenceManager = PreferenceManager.getDefaultSharedPreferences(this)
        prefChangeListener = MySharedPrefChangeListener()
        preferenceManager?.registerOnSharedPreferenceChangeListener(prefChangeListener)
    }
}

class MySharedPrefChangeListener : SharedPreferences.OnSharedPreferenceChangeListener {

    /**
     * Called when a shared preference is changed, added, or removed.
     */
    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
        if (sharedPreferences == null)
            return

        if (sharedPreferences.contains(key)) {
            // action to perform
        }
    }
}
于 2019-01-11T14:51:29.127 に答える
-2

最初のアプリで共有されているWordで読み取り可能なデータを読みながら、

交換

getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);

getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);

2番目のアプリで更新された値を取得するには、2番目のアプリで。

于 2013-02-11T19:01:07.207 に答える