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

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

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

如果我通过我的首选项屏幕(PreferenceActivity)更改首选项,我的事件不会在首选项更改时触发(因为它是一个单独的活动和对共享首选项的单独引用?)

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

谢谢!

编辑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
}
});
}
56655 次浏览

Why don't you just add a onSharedPreferenceChanged in the rest of the activities where the preferences could change?

The OnSharedPreferenceChangeListener gets garbage collected in your case if you use an anonymous class.

To solve that problem use the following code in PreferenceActivity to register and unregister a change listener:

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
}

Furthermore be aware that the listener only gets called if the actual value changes. Setting the same value again will not fire the listener.

see also SharedPreferences.onSharedPreferenceChangeListener not being called consistently

This happen because garbage collector. its works only one time. then the reference is collected as garbage. so create instance field for listener.

private OnSharedPreferenceChangeListener listner;


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

While reading Word readable data shared by first app,we should

Replace

getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);

with

getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);

in second app to get updated value in second app.

I arrived here, like many others, because my listener won't be fired when I changed my boolean from true to false, or viceversa.

After much reading, and refactoring, switching contexts/inner classes/privates/static/ and the like, I realized my (stupid) error:

The onSharedPreferenceChanged is only called if something changes. Only. Ever.

During my tests, I was so dumb to click on the same button all the time, thus assigning the same boolean value to the preference all the time, so it did not ever change.

Hope this helps somebody!!

One other way of avoiding the problem is to make your activity the listener class. Since there is only one override method with a distinctive name you can do this:

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

Note the original question spoke of a MainActivity listening to setting changes in a PreferenceActivity. The asker then added an "EDIT1" and changed the question to listening in the PreferenceActivity itself. That is easier than the former and seems to be what all the answers assume. But what if you still want the former scenario?

Well, it will work too, but do not use OnResume() and OnPause() to register and unregister the listener. Doing so will cause the listener to be ineffectual because the user leaves the MainActivity when they use the PreferenceActivity (which makes sense when you think about it). So it will work, but then your MainActivity will still be listening in the background even when the user is not using it. Kind of a waste of resources isn't it? So there is another solution that seems to work, simply add a method to OnResume() to re-read all preferences. That way when a user finishes editing preferences in a PreferenceActivity, the MainActivity will pick them up when the user returns to it and you don't need a listener at all.

Someone please let me know if they see a problem with this approach.

The garbage collector erases that... you should consider using an Application context instead...or just add the code when app launchs... and then add the the listener with application context...

Consider keeping PreferencesChangeListener inside Android App class instance. Although it's NOT a clean solution storing reference inside App should stop GC from garbage collecting your listener and you should still be able to receive DB change updates. Remember that preference manager does not store a strong reference to the listener! (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)
}
}

and

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