在SyncAdapter中提交的SharedPreference未在Activity中更新?

mat*_*sch 13 android sharedpreferences android-syncadapter

我在同步成功后在SyncAdapter中更改并提交SharedPreference,但是当我在Activity中访问首选项时,我没有看到更新的值(相反,我看到的是旧值).我究竟做错了什么?不同的上下文?

我在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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

服务使用ApplicationContext初始化SyncAdapter:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Application中调用的一个静态函数,用于检查SharedPreference.这不会返回SyncAdapter中提交的值,而是返回旧值.(我的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;
}
Run Code Online (Sandbox Code Playgroud)

更新:当我完全关闭应用程序时,我将获得新值(从正在运行的应用程序中滑动).我还有一个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);
}
Run Code Online (Sandbox Code Playgroud)

mat*_*sch 17

好吧,我通过@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>
Run Code Online (Sandbox Code Playgroud)

因此,我必须在我的应用程序的UI过程中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);
}
Run Code Online (Sandbox Code Playgroud)

  • 自API 23以来,不推荐使用MODE_MULTI_PROCESS. (9认同)