SharedPreferences в BroadcastReceiver, похоже, не обновляется?

У меня есть Activity, который обновляет строку в SharedPreferences.

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

Затем я запустил службу:

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

Служба создает ссылку на Alarm, которая расширяет BroadcastReceiver:

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

В SetAlarm я делаю все базовые настройки (на данный момент "имя пользователя" по-прежнему правильное.. я проверил):

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

Затем я останавливаю службу, а затем запускаю ее снова (используя 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);
}

Проблема в onReceive.. при первом правиле поле "имя пользователя". Во второй раз, если имя пользователя обновляется между остановкой и запуском службы, однако, оно возвращает первое значение. Значение, похоже, не обновляется...

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

Ответ 1

У меня была такая же проблема, и после долгих часов, чтобы решить ее, я, наконец, нашел проблему, вызвавшую ее. В вашем AndroidManifest у вас есть что-то вроде этого:

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

Последний атрибут (process: remote) заставляет приемник запускаться на другом/новом процессе, когда он вызывается. Но SharedPreferences НЕ поддерживается между различными процессами.

Итак, я сделал, чтобы удалить этот последний атрибут из манифеста. Импликация заключается в том, что код теперь будет работать в основном потоке, но если у вас есть только несколько строк, чтобы показать уведомление, это не должно быть проблемой. Другой способ - вызвать службу для выполнения длительной операции.

Ответ 2

К сожалению, решение Amir Naor не работало в моем Android 7 App. Кажется, что каждый приемник всегда запускается в новом процессе.

API < 23

Итак, если ваше приложение < API уровня 23, вы можете использовать флаг Context.MODE_MULTI_PROCESS:

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

API >= 23

Какой сюрприз. Поскольку API-уровень 23 является флагом Context.MODE_MULTI_PROCESS устарел, и мы должны использовать ContentProvider для совместного использования свойств между процессами.


В github есть очень хорошая библиотека: Лоток - замена SharedPreferences для Android. Эта библиотека является оберткой ContentProvider с некоторыми другими полезными функциями. Попробуйте.