I am changing and committing a SharedPreference in my SyncAdapter after successful sync, but I am not seeing the updated value when I access the preference in my Activity (rather I am seeing the old value). What am I doing wrong? Different Contexts?
My SyncAdapter where I update the preference:
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();
}
}
}
The Service initializing the SyncAdapter with the 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();
}
}
A static function within the Application called by the Activity that checks the SharedPreference. This does not return the value committed in the SyncAdapter, but the old value. (My SettingsActivity and other Activities also use the old value.):
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: I am getting the new value when I completely close the app (swipe it from the apps running). I also have a SharedPreferenceChangeListener, which is not fired when the preference is updated.
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);
}
Android stores Shared Preferences settings as XML file in shared_prefs folder under DATA/data/{application package} directory. The DATA folder can be obtained by calling Environment. getDataDirectory() .
Shared Preferences allow you to save and retrieve data in the form of key,value pair. In order to use shared preferences, you have to call a method getSharedPreferences() that returns a SharedPreference instance pointing to the file that contains the values of preferences.
You can create a new shared preference file or access an existing one by calling one of these methods: getSharedPreferences() — Use this if you need multiple shared preference files identified by name, which you specify with the first parameter. You can call this from any Context in your app.
Ok, I figured it out myself with @Titus help and after some research and pieced together a solution for my problem.
The reason why the DefaultSharedPreferences
of the same Context
are not updated is that I have specified the SyncService
to run in its own process in the AndroidManifest.xml
(see below). Hence, starting from Android 2.3, the other process is blocked from accessing the updated SharedPreferences
file (see this answer and the Android docs on 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>
So I had to set MODE_MULTI_PROCESS
when accessing the SharedPreferences
both in the SyncAdapter
and in the UI process of my app. Because I've used PreferenceManager.getDefaultSharedPreferences(Context)
extensively throughout the app I wrote a utility method and replaced all calls of PreferenceManager.getDefaultSharedPreferences(Context)
with this method (see below). The default name of the preferences file is hardcoded and derived from the Android source code and this answer.
public static SharedPreferences getDefaultSharedPreferencesMultiProcess(
Context context) {
return context.getSharedPreferences(
context.getPackageName() + "_preferences",
Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With