2014-10-16 45 views
13

成功同步后,我正在更改并在SyncAdapter中提交SharedPreference,但在访问我的Activity中的首选项时(而非看到旧值),我没有看到更新的值。我究竟做错了什么?不同的上下文?在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(); 
     } 
    } 
} 

的服务初始化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(); 
    } 
} 

通过检查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; 
} 

更新:我收到的时候我完全关闭该应用程序(从应用程序运行刷卡吧)的新值。我还有一个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); 
} 
+0

从你已经发布的代码似乎你从来没有叫'startSync()'的'SyncAdapter'这意味着'onPerformSync(...)'方法不执行和偏好从不改变。 – Titus 2014-10-16 16:10:10

+0

@Titus我在某处执行'onPerformSync()'是肯定执行的。它也在随后的同步中使用新值。我发现'SyncService'运行在一个单独的进程中('”)。现在我正试图弄清楚如何在'PreferenceManager.getDefaultSharedPreferences()'中使用'MODE_MULTI_PROCESS'。 – matsch 2014-10-16 16:18:28

+0

您可以使用'prefs = mContext.getSharedPreferences(“myAppPrefs”,Context.MODE_MULTI_PROCESS);'[Here](http://developer.android.com/reference/android/content/Context.html#getSharedPreferences(java.lang .String,int))是文档。 – Titus 2014-10-16 16:26:53

回答

16

好吧,我用@Titus的帮助和经过一些研究并将我的问题拼凑在一起解决了一个问题。

为什么不更新相同ContextDefaultSharedPreferences的原因是,我所指定的SyncService在自己的进程中AndroidManifest.xml运行(见下文)。因此,从Android 2.3开始,另一个进程被阻止访问更新的SharedPreferences文件(请参阅this answerContext.MODE_MULTI_PROCESS上的Android文档)。

<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> 

所以我不得不在SyncAdapter和我的应用程序的UI进程访问SharedPreferences时都设置MODE_MULTI_PROCESS。因为我在整个应用程序中广泛使用了PreferenceManager.getDefaultSharedPreferences(Context),所以我编写了实用程序方法,并用此方法替代了所有PreferenceManager.getDefaultSharedPreferences(Context)调用(请参阅下文)。首选项文件的默认名称是硬编码的,从the Android source codethis answer派生。

public static SharedPreferences getDefaultSharedPreferencesMultiProcess(
     Context context) { 
    return context.getSharedPreferences(
      context.getPackageName() + "_preferences", 
      Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); 
} 
+0

根据http://stackoverflow.com/a/6310080/8524上述代码将获得与SharedPreferences.getDefaultSharedPreferences()相同的'SharedPreferences'对象。 – Diederik 2015-10-02 08:08:38

+1

是的,它会得到相同的对象,但是使用'Context.MODE_MULTI_PROCESS'修饰符集。我将链接到您在最后一段中的相同答案。 – matsch 2015-10-02 13:35:51

+0

我认为你的回答很好。如果任何人(如我)使用'SharedPreferences.getDefaultSharedPreferences()'获取共享首选项,然后意识到他们需要多进程访问权限,我添加了注释。 – Diederik 2015-10-02 14:24:46

0

由于SharedPreferences不是过程安全,我不会建议使用AbstractThreadedSyncAdapter另一个进程中,除非你真的需要它。

Why do i need multiple processes in my application?

解决方案

取下您在清单中声明的​​服务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> 
+0

感谢它为我工作。 – 2017-05-30 20:19:24

0

在我的情况下,我试图从BroadcastReceiver启动的服务访问SharedPreferences。

我从AndroidManifest.xml中的声明中删除了android:process=":remote"以使其起作用。

<receiver 
    android:process=":remote" 
    android:name=".Alarm"> 
</receiver> 
相关问题