Одной из альтернатив использования SQLite на Android является хранение объектов Java в SharedPreferences . Здесь мы рассмотрим два разных способа сделать это.
Почему бы не перейти на SQLite для всех нужд хранения? Причины могут быть разными: помимо несоответствия импеданса между объектной ориентацией и реляционными базами данных, SQLite может быть излишним (влечет за собой дополнительные издержки) для некоторых простых случаев использования, или его использование и синтаксис могут вообще не нравиться.
В качестве примера мы будем работать со следующим классом User :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
/** User object to be saved in db */ public class User{ private int id; // used for object storage private String userName; private boolean registered; private double score; /** Constructor */ public User( int id, String userName, boolean registered, double score){ this .id = id; this .userName = userName; this .registered = registered; this .score = score; } // getters and setters here... } |
Уникальный идентификатор идентификатора , скорее всего, будет передан нашим сервером, хотя мы также можем вычислить его на самом устройстве, как только мы создадим пользователя и сохраним его отдельно в SharedPreferences , в зависимости от дизайна нашего приложения. Здесь мы просто будем использовать его как ключ хранения объекта.
Далее нам нужно написать наш класс настроек:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/** stores the user object in SharedPreferences */ public class UserPrefs{ /** This application's preferences label */ private static final String PREFS_NAME = "com.our.package.UserPrefs" ; /** This application's preferences */ private static SharedPreferences settings; /** This application's settings editor*/ private static SharedPreferences.Editor editor; /** Constructor takes an android.content.Context argument*/ public UserPrefs(Context ctx){ if (settings == null ){ settings = ctx.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE ); } /* * Get a SharedPreferences editor instance. * SharedPreferences ensures that updates are atomic * and non-concurrent */ editor = settings.edit(); } //... } |
Метод 1: Плоские объекты с полевыми ключами
Идея здесь в том, что, хотя SharedPreferences хранит только примитивные типы, объектная конструкция в конечном итоге является «мешком» примитивов. Таким образом, мы можем разложить объект на набор примитивов и сохранить каждый из них индивидуально с уникальным ключом. Однако нам нужно отслеживать, какое сохраненное поле принадлежит какому объекту, если мы хотим восстановить наши объекты из хранилища.
Поэтому, прежде чем писать методы CRUD для данного объекта User в нашем классе UserPrefs , нам нужно определить уникальные ключи для каждого члена класса User. Для удобства мы можем написать метод обеспечения уникальности ключа по всем направлениям:
01
02
03
04
05
06
07
08
09
10
11
12
|
/** The prefix for flattened user keys */ public static final String KEY_PREFIX = "com.our.package.KEY" ; /** Method to return a unique key for any field belonging to a given object * @param id of the object * @param fieldKey of a particular field belonging to that object * @return key String uniquely identifying the object's field */ private String getFieldKey( int id, String fieldKey) { return KEY_PREFIX + id + "_" + fieldKey; } |
Обратите внимание, как getFieldKey () дает нам уникальный идентификатор для имени поля и для пользователя.
Теперь мы можем приступить к написанию методов CRUD:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
/** generic field keys */ private static final String KEY_USERNAME = "com.our.package.KEY_USERNAME" ; private static final String KEY_REGISTERED = "com.our.package.KEY_REGISTERED" ; private static final String KEY_SCORE = "com.our.package.KEY_SCORE" ; /** Store or Update */ public void setUser(User user){ if (user == null ) return ; // don't bother int id = user.getId(); editor.putString( getFieldKey(id, KEY_USERNAME), user.getUsername() ); editor.putBoolean( getFieldKey(id, KEY_REGISTERED), user.isRegistered() ); editor.putFloat( getFieldKey(id, KEY_SCORE), user.getScore() ); editor.commit(); } /** Retrieve */ public User getUser( int id){ String name = settings.getString( getFieldKey(id, KEY_USERNAME), "" ); // default value boolean registered = settings.getBoolean( getFieldKey(id, KEY_REGISTERED), false ); // default value double score = settings.getFloat( getFieldKey(id, KEY_SCORE), 0 ); // default value return new User(id, name, registered, score); } /** Delete */ public void deleteUser(User user){ if (user == null ) return ; // don't bother int id = user.getId(); editor.remove( getFieldKey(id, KEY_USERNAME) ); editor.remove( getFieldKey(id, KEY_REGISTERED) ); editor.remove( getFieldKey(id, KEY_SCORE) ); editor.commit(); } |
Теперь мы можем создавать, извлекать, обновлять и удалять любые объекты пользователя из любой точки нашего приложения:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
// get a SharedPreferences instance UserPrefs prefs = new UserPrefs( this .getApplicationContext() ); // get id from server or local storage // then find User with that id User user = prefs.getUser(id); // operations on User, e.g. user.setRegistered( true ); user.setScore(new_score); // save prefs.setUser(user); // ...or delete prefs.deleteUser(user), |
Для встроенных объектов мы применяем ту же логику рекурсивно и вызываем их методы получения / установки из наших пользовательских методов CRUD. Этот метод выравнивания объектов представляет собой простое альтернативное хранилище без использования SQL на телефоне. Это, конечно, имеет свои ограничения по мере увеличения количества вложенных объектов.
Способ 2: Google Gson
Gson — это библиотека Java, которая предоставляет простые методы toJson () и fromJson () для преобразования объектов Java в формат JSON и наоборот.
Затем мы просто сохраняем формат JSON как целую строку в SharedPreferences . Этот метод предполагает добавление новой библиотеки в наши проекты, но он значительно удобнее:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
// convert User object user to JSON format Gson gson = new Gson(); String user_json = gson.toJson(user); // store in SharedPreferences String id = "" + user.getId(); // get storage key editor.putString(id, user_json); editor.commit(); // time flies... // do the reverse operation user_json = settings.getString(id, "" ); user = gson.fromJson(user_json, User. class ); |
Предыдущие методы CRUD теперь можно переписать в нашем классе UserPrefs без необходимости использовать другие ключи, кроме идентификаторов пользователей. Это должно быть просто и оставлено читателю в качестве упражнения.
Вывод
Мы рассмотрели несколько способов использования SharedPreferences для хранения объектов. Другими вариантами работы с объектами являются несколько ORM для Android ( ORMLite , greenDAO , Sugar ORM , ActiveAndroid и т. Д.) Или мобильные базы данных NOSQL, такие как Couchbase Lite (бета-версия в настоящее время). Couchbase Lite — это, по сути, база данных JSON, в то время как различные ORM могут существенно упростить наш код, когда модель данных становится сложной, и мы находимся в процессе написания множества стандартных операций SQLite. Как и в случае со всеми абстракциями, нацеленными на уменьшение базовой сложности, недостатком ORM является закон утечек :
Все нетривиальные абстракции, в какой-то степени, негерметичны.
Альтернативы ORM и NOSQL станут темами будущих статей.