如果在单独的活动中发生更改,则不会触发onSharedPreferenceChanged吗?


70

我已经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
        }
    });
}

Answers:


142

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


3
噢,你真摇滚!多么棘手!!! 我的onsharedpreferencelistener正在被垃圾收集!因此,根据您的链接,我为它创建了一个长期引用(全局成员变量),瞧,它很棒!
布莱德·海因

@pivotnig当我尝试您的代码时,出现编译错误。它是PreferenceActivity子类,因此不会接受。代码中还有其他内容吗?

@dpk没有告诉我错误,很难说是什么问题。无论如何,您应该为您的问题提出一个新问题。
thumbmunkeys

1
兄弟,你真棒。感谢你的回答。(y)
Mukul Goel 2014年

1
好答案!即时帮助
安东

17

发生这种情况是因为垃圾收集器。它的作品只有一次。然后将引用作为垃圾收集。因此,为侦听器创建实例字段。

private OnSharedPreferenceChangeListener listner;

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

1
我认为这个答案最接近这个问题。如果在调用站点中正确定义了侦听器,则似乎是垃圾回收器。因此,应该在其他地方保留对侦听器的引用,以使其正常工作。
Petr Gladkikh 2013年

@hderanga谢谢,这对我有用,因为我的课没有扩展PreferenceActivity
user2814778 2015年

有内存泄漏问题吗?
jfly

7

我来到这里,和许多人一样,因为当我改变了我的布尔我的听众不会被解雇truefalse,或者反之亦然。

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

onSharedPreferenceChanged唯一的,如果有新的变化叫。只要。曾经

在测试期间,我总是无聊地单击相同的按钮,因此始终将相同的布尔值分配给首选项,因此它永远都不会改变。

希望这对某人有帮助!!


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)
    {
        ...
    }
} 

1
这是我正在做的,但是没有用。除其他外,我发现使用OnResume()和OnPause()分别注册和取消注册侦听器将导致侦听器无效,因为用户在使用PreferenceActivity时会离开MainActivity(这在您考虑时是有道理的)。
2016年

1

请注意,最初的问题是MainActivity监听PreferenceActivity中的设置更改。然后,询问者添加了“ EDIT1”,并将问题更改为在PreferenceActivity本身中进行侦听。这比前者容易,而且似乎是所有答案所假定的。但是,如果您仍然希望使用前一种方案,该怎么办?

很好,它也可以工作,但是不要使用OnResume()和OnPause()来注册和取消注册侦听器。这样做将导致侦听器无效,因为用户在使用PreferenceActivity时会离开MainActivity(这在您考虑时是有道理的)。这样就可以了,但是即使用户不使用它,MainActivity仍然会在后台监听。是不是有点浪费资源?因此,还有另一种似乎可行的解决方案,只需向OnResume()添加一个方法即可重新读取所有首选项。这样,当用户完成在PreferenceActivity中的首选项编辑时,MainActivity将在用户返回首选项时选择它们,而您根本不需要侦听器

如果有人看到此方法有问题,请告诉我。


0

您为什么不只onSharedPreferenceChanged在其他活动中添加一个可以更改首选项的活动?


您的意思是像在我的设置活动中定义onSharedPreferenceChanged一样吗?我做到了,而且没有开火。
布莱德·海因

记录下来,问题是由垃圾收集器回收了我的事件处理程序引起的。我必须创建对事件处理程序的全局成员引用。
布莱德·海因

0

垃圾收集器消除了这一点...您应该考虑改用Application上下文...或者只是在应用启动时添加代码...,然后将侦听器与应用上下文一起添加...


0

考虑将PreferencesChangeListener保留在Android App类实例中。尽管这不是一个干净的解决方案,但在App内存储引用应该可以阻止GC垃圾回收您的侦听器,并且您仍然应该能够接收数据库更改更新。请记住,首选项管理器不会存储对侦听器的强引用!(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
        }
    }
}

-2

在读取第一个应用程序共享的Word可读数据时,我们应该

更换

getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);

getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);

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


1
Android不支持SharedPreferences从多个进程进行访问。这样做会导致并发问题,这可能导致所有首选项丢失。此外,MODE_MULTI_PROCESS不再受支持。
山姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.