web-dev-qa-db-ja.com

別のアクティビティで変更が発生した場合、onSharedPreferenceChangedは発生しませんか?

メインアクティビティにonSharedPreferenceChangedを実装しました。

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

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

誰も私がこの状況を克服する方法についての勧告を持っていますか?

ありがとう!

EDIT1:自分の設定アクティビティにイベントハンドラーを追加しようとしましたが、起動しません。次のメソッドは、設定アクティビティの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
        }
    });
}
68
Brad Hein

匿名クラスを使用する場合、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が一貫して呼び出されない も参照してください

135
thumbmunkeys

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

private OnSharedPreferenceChangeListener listner;

listner = new SharedPreferences.OnSharedPreferenceChangeListener() {        
        @Override
        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
            //implementation goes here
        }
    };
    prefs.registerOnSharedPreferenceChangeListener(listner);
14
hderanga

ブール値をtrueからfalseに、またはその逆に変更してもリスナーが起動しないため、他の多くの人と同様にここに到着しました。

contexts/innerclasses/privates/static/などを切り替えて読み、リファクタリングした後、私は(愚かな)エラーに気付きました。

onSharedPreferenceChangedonlyが変更された場合に呼び出されます。のみ。今まで。

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

これが誰かを助けることを願っています!!

6
mrArias

問題を回避するもう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)
    {
        ...
    }
} 
3
Steve Waring

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

まあ、それも動作しますが、OnResume()とOnPause()を使用してリスナーを登録および登録解除しないでください。そうすると、ユーザーがPreferenceActivityを使用するときにMainActivityを離れるので、リスナーは無効になります(これについて考えると理にかなっています)。したがって、動作しますが、ユーザーが使用していない場合でも、MainActivityはバックグラウンドで引き続きリッスンします。リソースの浪費のようなものではありませんか?動作するように思われる別のソリューションがあります。OnResume()にメソッドを追加して、すべての設定を再読み込みします。このようにして、ユーザーがPreferenceActivityの設定の編集を終了すると、MainActivityはユーザーがそれに戻ったときにそれらを取得しますリスナーはまったく必要ありません

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

1
trans

設定が変更される可能性のある残りのアクティビティにonSharedPreferenceChangedを追加しないのはなぜですか?

0
Cristian

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

0
superUser

PreferencesChangeListenerをAndroid Appクラスインスタンスに保存することを検討してください。 App内の参照は、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
        }
    }
}