SharedPreferences in BroadcastReceiver seems to not update?

I have a Activity which updates a string in the SharedPreferences.

SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = settings.edit();
editor.putString("username", username);
editor.commit();

I then start a service:

startService(new Intent(this, MyService.class));

The service creates a reference to Alarm which extends BroadcastReceiver:

Alarm alarm = null;
public void onCreate() {
    alarm = new Alarm();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    alarm.SetAlarm(this);
}

In SetAlarm I do all the basic setting up stuff (At this point, "username" is still correct.. i checked):

public void SetAlarm(Context context) {
    AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
    am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 1000 * 60 * interval, pi);
}

I then stop the service and then start it again (using SetAlarm).

public void CancelAlarm(Context context) {
   Intent intent = new Intent(context, Alarm.class);
   PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
   AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
   alarmManager.cancel(sender);
}

The issue is in onReceive.. the first time the "username" field is correct. The second time, if username is updated between the service stopping and starting, however, it returns the first value. The value does not seem to get updated...

public void onReceive(Context context, Intent intent) {   
    SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
    Log.e("hi", settings.getString("username", ""));
}

Answers


I had the same problem and after struggling for hours to solve it, I finally found the issue causing it. In your AndroidManifest you probably have something like that:

<receiver android:name="AlarmReceiver" android:process=":remote" />

The last attribute (process:remote) cause the receiver to run on a different/new process when it is called. But SharedPreferences is NOT supported between different processes.

So what I did is to remove that last attribute from the manifest. The implication is that the code will now run on the main thread - but if you only have a few lines to show a notification then that shouldn't be a problem. Another way is to call a service to run the long operation.


Unfortunately the solution by Amir Naor not worked in my Android 7 App. It seems that every receiver get always started in a new process.

API < 23

So if your app < API Level 23, you can use the flag Context.MODE_MULTI_PROCESS:

context.getSharedPreferences("mypreferences", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);

API >= 23

What a surprise. Since API Level 23 is the flag Context.MODE_MULTI_PROCESS deprecated and we should use ContentProvider to share the Properties between processes.


There is a very nice library on github: Tray - a SharedPreferences replacement for Android. This library is a ContentProvider wrapper with some other useful features. Give it a try.


Need Your Help

inject bean reference into a Quartz job in Spring?

spring quartz-scheduler inject

I managed to configure and schedule a Quartz job using JobStoreTX persistent store in Spring. I do not use Spring's Quartz jobs, because I need to schedule them dynamically, at run time, and all

Why does Boost property tree write_json save everything as string? Is it possible to change that?

json boost boost-propertytree

I'm trying to serialize using boost property tree write_json, it saves everything as strings, it's not that data are wrong, but I need to cast them explicitly every time and I want to use them some...