Подтвердить что ты не робот

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

Ответ 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>