Использование SharedPreferences в многопроцессном режиме
Я определил экземпляр SharedPreferences
, который используется в многопроцессном режиме.
public class Prefs {
private static SharedPreferences prefs;
private static SharedPreferences.Editor editor;
private static void init(Context context) {
prefs = context.getSharedPreferences("alaki",
Context.MODE_MULTI_PROCESS);
editor = prefs.edit();
}
// static methods to set and get preferences
}
Теперь я использую этот класс для службы с отдельным процессом, а также в моем основном процессе приложения статическим способом.
Все идет хорошо, но иногда удаляются все сохраненные данные на экземпляре SharedPreferences!
Как я могу решить эту проблему?
Изменить:
Наконец, я решил проблему с помощью IPC.
Ответы
Ответ 1
В настоящее время нет способа безопасного доступа к SharedPreferences
для нескольких процессов, как описано в документации.
Примечание. Этот класс не поддерживает использование нескольких процессов.
После многого тестирования с помощью MODE_MULTI_PROCESS
у меня есть три испытания:
1- Инициализируйте SharedPreferences
один раз в каждом процессе и используйте его несколько раз.
Проблема: Значения не отражаются в каждом процессе, как ожидалось. Таким образом, каждый процесс имеет собственное значение SharedPreferences.
2- Инициализировать SharedPreferences
в каждом столбце put или get.
Это действительно работает, и теперь значение становится взаимозаменяемым между процессами.
Проблема: иногда после активного доступа к sharedpref файл общих предпочтений удалялся со всем его содержимым, как описано в этом проблема, и я получаю это предупреждение в журнале:
W/FileUtils﹕ Failed to chmod(/data/data/com.hegazy.multiprocesssharedpref/shared_prefs/myprefs.xml): android.system.ErrnoException: chmod failed: ENOENT (No such file or directory)
Вы можете узнать, почему это происходит в этой проблеме.
3- Используйте синхронизацию для блокировки методов, которые помещают и получают значения в SharedPreferences
.
Это совершенно неправильно; синхронизация не работает в разных процессах. SharedPreferences
фактически использует синхронизацию в своей реализации, но только обеспечивает безопасность потоков, а не безопасность процесса. Это описано очень хорошо здесь.
Ответ 2
Собственные файлы SharedPreferences не являются безопасными для процесса. Вероятно, поэтому Документация SharedPreferences говорит
Примечание. В настоящее время этот класс не поддерживает использование нескольких процессов. Это будет добавлено позже.
Ответ 3
С помощью метода commit()
сохраняются изменения в постоянном хранилище, поэтому он медленный и конфликтует с несколькими вызовами из других процессов.
Однако существует альтернатива этому методу, вы должны вызвать метод apply()
, этот метод сохраняет изменения в памяти, а затем на дисковой памяти асинхронно, поэтому он более надежный.
Ответ 4
Я работал над этим, комбинируя:
- Предоставление каждому процессу взаимоисключающего доступа к файлу
SharedPreferences
(например, с помощью механизма блокировки на основе сокетов)
- Повторно инициализировать
SharedPreferences
с помощью флага MODE_MULTI_PROCESS
каждый раз, когда вы хотите использовать его для обхода кэширования в памяти
Кажется, что это работает нормально, но он не был полностью протестирован в реальном мире, поэтому я не знаю, насколько он надежен.
Вы можете увидеть рабочий пример, который я написал здесь.
Предупреждение. Похоже, MODE_MULTI_PROCESS
устарел в Android M. Он может перестать работать в будущем.
Ответ 5
напоминает, что использование контекстных объектов как статического поля, у вас есть риск утечки контекста, потому что не объявлять объект в классе приложения
public class CustomApplication extends Application{
private Prefs prefs;
public void onCreate(){
prefs = new Prefs(this);
}
public Prefs getPrefs(){
return prefs;
}
}
Из любого контекста вы можете получить префы
((MyApplication)context.getApplicationContext()).getPrefs();
Ответ 6
Используйте поставщика контента, который использует SharedPreferences. Пример можно посмотреть здесь: https://github.com/hamsterksu/MultiprocessPreferences
Ответ 7
Если два процесса записывают данные в SharedPreferences, возможно, все значения SharedPreferences будут reset равными значениям по умолчанию.
Также вы можете попробовать вызвать clear()
в редакторе перед сохранением val
SharedPreferences.Editor sp = settings.edit();
sp.clear();
sp.putString("Name", "YourName");
sp.commit();