74

我已经onSharedPreferenceChanged在我的主要活动中实施了。

如果我更改主要活动中的首选项,我的事件就会触发。

如果我通过我的首选项屏幕PreferenceActivity

有没有人建议我应该如何克服这种情况?

谢谢!

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

这是因为垃圾收集器。它只工作一次。然后将引用作为垃圾收集。所以为监听器创建实例字段。

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

我和其他许多人一样来到这里,因为当我将布尔值从trueto更改为 时,我的听众不会被解雇false,反之亦然。

经过大量阅读、重构、切换contexts/inner classes/privates/static/等,我意识到我的(愚蠢的)错误:

只有在发生变化onSharedPreferenceChanged才会调用。仅有的。曾经。

在我的测试中,我一直在点击同一个按钮,因此一直为首选项分配相同的布尔值,所以它永远不会改变。

希望这对某人有帮助!

于 2013-10-10T13:00:33.700 回答
3

避免该问题的另一种方法是使您的活动成为侦听器类。由于只有一个具有独特名称的覆盖方法,您可以这样做:

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

请注意,最初的问题是关于 MainActivity 监听 PreferenceActivity 中的设置更改。然后提问者添加了一个“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保留在 Android App类实例中。虽然它不是一个在 App 内存储引用的干净解决方案,但应该阻止 GC 垃圾收集您的侦听器,并且您仍然应该能够接收数据库更改更新。请记住,偏好管理器不会存储对侦听器的强引用!(弱哈希映射

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

在第二个应用程序中获取第二个应用程序中的更新值。

于 2013-02-11T19:01:07.207 回答