SharedPreference, зафиксированное в SyncAdapter, не обновленном в Activity?
Я изменяю и передаю SharedPreference в моем SyncAdapter после успешной синхронизации, но я не вижу обновленного значения, когда я получаю доступ к предпочтению в своей работе (скорее, я вижу старое значение). Что я делаю не так? Различные контексты?
Мой SyncAdapter, где я обновляю предпочтение:
class SyncAdapter extends AbstractThreadedSyncAdapter {
private int PARTICIPANT_ID;
private final Context mContext;
private final ContentResolver mContentResolver;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mContext = context;
mContentResolver = context.getContentResolver();
}
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
mContext = context;
mContentResolver = context.getContentResolver();
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
PARTICIPANT_ID = Integer.parseInt(prefs.getString("participant_id", "0"));
if (success) {
// save and set the new participant id
PARTICIPANT_ID = newParticipantId;
prefs.edit().putString("participant_id", String.valueOf(newParticipantId)).commit();
}
}
}
Служба, инициализирующая SyncAdapter с помощью ApplicationContext:
public class SyncService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static SyncAdapter sSyncAdapter = null;
@Override
public void onCreate() {
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), false);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
Статическая функция в приложении, вызываемая Activity, которая проверяет SharedPreference. Это не возвращает значение, зафиксированное в SyncAdapter, но старое значение. (My SettingsActivity и другие действия также используют старое значение.):
public static boolean isUserLoggedIn(Context ctx) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
int participantId = Integer.parseInt(prefs.getString("participant_id", "0"));
LOGD("dg_Utils", "isUserLoggedIn.participantId: " + participantId);// TODO
if (participantId <= 0) {
ctx.startActivity(new Intent(ctx, LoginActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
return false;
}
return true;
}
UPDATE: Я получаю новое значение, когда полностью закрываю приложение (проведите его по экрану из приложений). У меня также есть SharedPreferenceChangeListener, который не запускается, когда предпочтение обновляется.
private final SharedPreferences.OnSharedPreferenceChangeListener mParticipantIDPrefChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("participant_id")) {
LOGI(TAG, "participant_id has changed, requesting to restart the loader.");
mRestartLoader = true;
}
}
};
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// subscribe to the participant_id change lister
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
PARTICIPANT_ID = Integer.parseInt(prefs.getString("participant_id", "0"));
prefs.registerOnSharedPreferenceChangeListener(mParticipantIDPrefChangeListener);
}
Ответы
Ответ 1
Хорошо, я понял это с помощью @Titus и после некоторого исследования и собрал решение для своей проблемы.
Причина, по которой DefaultSharedPreferences
того же Context
не обновляется, заключается в том, что я указал SyncService
для запуска в своем собственном процессе в AndroidManifest.xml
(см. ниже). Следовательно, начиная с Android 2.3, другой процесс блокируется от доступа к обновленному файлу SharedPreferences
(см. этот ответ и документам Android на Context.MODE_MULTI_PROCESS
).
<service
android:name=".sync.SyncService"
android:exported="true"
android:process=":sync"
tools:ignore="ExportedService" >
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
Поэтому мне приходилось устанавливать MODE_MULTI_PROCESS
при обращении к SharedPreferences
как в SyncAdapter
, так и в процессе пользовательского интерфейса моего приложения. Поскольку я широко использовал PreferenceManager.getDefaultSharedPreferences(Context)
во всем приложении, я написал метод утилиты и заменил все вызовы PreferenceManager.getDefaultSharedPreferences(Context)
на этот метод (см. Ниже). Имя файла настроек по умолчанию жестко запрограммировано и получено из исходный код Android и этот ответ.
public static SharedPreferences getDefaultSharedPreferencesMultiProcess(
Context context) {
return context.getSharedPreferences(
context.getPackageName() + "_preferences",
Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
}
Ответ 2
Так как SharedPreferences не являются безопасными процессами, я бы не рекомендовал использовать AbstractThreadedSyncAdapter в другом процессе, если вам это действительно не нужно.
Зачем мне нужно несколько процессов в моем приложении?
Решение
Удалите android:process=":sync"
из Сервиса, который вы указали в своем манифесте!
<service
android:name=".sync.SyncService"
android:exported="true"
android:process=":sync"
tools:ignore="ExportedService" >
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
Ответ 3
В моем случае я пытался получить доступ к SharedPreferences из службы, запущенной BroadcastReceiver.
Я удалил android:process=":remote"
из объявления в AndroidManifest.xml, чтобы заставить его работать.
<receiver
android:process=":remote"
android:name=".Alarm">
</receiver>