public static final String DATABASE_NAME

advertisement
Платформа Android
Ведущий семинара: Максим Лейкин, компания «МЕРА НН»
Виды хранилищ данных
На платформе Android имеются следующие варианты
хранения данных:
• Shared Preferences
позволяет хранить набор пар «ключ-значение»
• Files
позволяет хранить данные произвольного типа
• SQL Lite DB
позволяет создавать локальные базы данных
• Content Providers
Интерфейс для доступа к данным, полученным из
разных источников
Shared Preferences
С помощью Shared Preferences можно создавать
именованные наборы пар «ключ-значение», которые могут
совместно использоваться приложениями работающими в
одном контексте (application context). Чаще всего
используются для передачи данных между
пользовательскими сессиями и компонентами одного
приложения.
Поддерживаются типы: boolean, string, float, long, integer.
Shared Preferences
Создание/модификация shared preferences:
protected void savePreferences() {
// Create or retrieve the shared preference object.
public static final String MYPREFS = “mySharedPreferences”;
int mode = Activity.MODE_PRIVATE;
SharedPreferences mySharedPreferences = getSharedPreferences(MYPREFS, mode);
// Retrieve an editor to modify the shared preferences.
SharedPreferences.Editor editor = mySharedPreferences.edit();
// Store new primitive types in the shared preferences object.
editor.putBoolean(“isTrue”, true);
editor.putFloat(“lastFloat”, 1f);
editor.putInt(“wholeNumber”, 2);
editor.putLong(“aNumber”, 3l);
editor.putString(“textEntryValue”, “Not Empty”);
// Commit the changes.
editor.commit();
}
Shared Preferences
Чтение shared preferences:
public void loadPreferences() {
// Get the stored preferences
public static final String MYPREFS = “mySharedPreferences”;
int mode = Activity.MODE_PRIVATE;
SharedPreferences mySharedPreferences = getSharedPreferences(MYPREFS, mode);
// Retrieve the saved values.
boolean isTrue = mySharedPreferences.getBoolean(“isTrue”, false);
float lastFloat = mySharedPreferences.getFloat(“lastFloat”, 0f);
int wholeNumber = mySharedPreferences.getInt(“wholeNumber”, 1);
long aNumber = mySharedPreferences.getLong(“aNumber”, 0);
String stringPreference;
stringPreference = mySharedPreferences.getString(“textEntryValue”,“”);
}
Сохранение состояния активностей
Каждая активность поддерживает внутри себя
безымянный SharedPreferences объект, доступ к которому
ограничен этой активностью. Его можно использовать для
сохранения данных, специфичных для данной активности.
protected void saveActivityPreferences() {
// Create or retrieve the activity preferences object.
SharedPreferences activityPreferences = getPreferences(Activity.MODE_PRIVATE);
// Retrieve an editor to modify the shared preferences.
SharedPreferences.Editor editor = activityPreferences.edit();
// Retrieve the View
TextView myTextView = (TextView)findViewById(R.id.myTextView);
// Store new primitive types in the shared preferences object.
editor.putString(“currentTextValue”,
myTextView.getText().toString());
// Commit changes.
editor.commit();
}
Сохранение состояния активностей
Каждая активность поддерживает внутри себя объект
Bundle, который автоматически передается качестве
параметра в метод: onCreate(Bundle icicle)
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView myTextView = (TextView)findViewById(R.id.myTextView);
String text = “”;
if (icicle != null && icicle.containsKey(TEXTVIEW_STATE_KEY)) {
text = icicle.getString(TEXTVIEW_STATE_KEY);
}
myTextView.setText(text);
}
Сохранение состояния активностей
Сохранять состяние активностей надо в методе onPause()
public void onPause() {
super.onPause();
SharedPreferences settings=getPreferences(0);
SharedPreferences.Editor editor=settings.edit();
editor.putBoolean("cb_checked", cb.isChecked());
editor.commit();
}
Восстанавливать в onResume()
public void onResume() {
super.onResume();
SharedPreferences settings=getPreferences(0);
cb.setChecked(settings.getBoolean("cb_checked", false));
}
Работа с файлами
Файлы можно хранить:
-в ресурсах
-во внутреннем хранилище (видны только самому
приложению)
- во внешнем хранилище (виды извне)
Файлы как статические ресурсы
Хранятся в каталоге /res/raw
Доступ из кода осуществляется через метод:
Resources getResources()
Далее полученный статический ресурс считвается как
байтовый поток ввода.
Внимание! Данный способ подразумевает, что файлы
можно только читать, но нельзя модифицировать.
InputStream
in=getResources().openRawResource(R.raw.words);
Файлы во внутреннем хранилище
Открыть файл для чтения:
public FileInputStream openFileInput (String name)
Открыть файл для записи (создать если не существует):
public FileOutputStream openFileOutput (String name, int mode)
name – имя файла (без путей!!!)
mode – режим записи:
Context.MODE_PRIVATE - созданный файл будет доступен только
приложению, создавшему его
Context.MODE_APPEND - если файл существует, то информация
дописывается в конец
Файлы во внутреннем хранилище
Полезные методы:
File getFilesDir() – путь к внутреннему хранилищу.
File getDir() – создает (или открывает) каталог внутреннего
хранилища.
boolean deleteFile() – удаляет файл из внутреннего
хранилища.
String[ ] fileList() – возвращает массив файлов,
сохраненных данным приложением
Файлы во внешнем хранилище
Внешнее хранилище может физически находиться на SDкарте, а может во внутренней памяти телефона (зависит от
модели)
Файлы во внешнем хранилище
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
Проверка доступности внешнего хранилища
на запись
}
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
Проверка доступности внешнего
хранилища на чтение
Файлы во внешнем хранилище
Создание файла во внешнем хранилище:
String root = Environment.getExternalStorageDirectory().toString();
File dir = new File (root + "/download");
dir.mkdirs();
File file = new File(dir, FILENAME_SD);
try {
FileOutputStream f = new FileOutputStream(file);
PrintWriter pw = new PrintWriter(f);
pw.println("Hi , How are you");
pw.flush();
pw.close();
f.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Базы данных SQLite
В платформу Android встроена полноценная
реляционная СУБД SQLite (www.sqlite.org )
Создаваемые приложением базы данных хранятся в:
/data/data/your.app.package/databases/your-db-name.db
и доступны только создавшему их приложению.
SQLite не поддерживает некоторые функции
настольных СУБД: FOREIGN KEY, вложенные
транзакции, RIGHT OUTER JOIN, FULL OUTER JOIN,
etc.
Базы данных SQLite
Создание схемы базы данных (наследование от класса
BaseColumns обеспечивает автоматическое добавление
поля _ID, содержащего первичный ключ:
import android.provider.BaseColumns;
public class DBScheme {
public static abstract class Vendors implements BaseColumns {
public static final String TABLE_NAME = "vendors";
public static final String COLUMN_NAME_ID = "vendor_id";
public static final String COLUMN_NAME_TITLE = "vendor_name";
public static final String COLUMN_NAME_COUNTRY = "vendor_country";
}
public static abstract class Models implements BaseColumns {
public static final String TABLE_NAME = "models";
public static final String COLUMN_NAME_ID = "model_id";
public static final String COLUMN_NAME_TUTLE = "model_name";
public static final String COLUMN_NAME_VENDOR_ID = "vendor_id";
}
}
Базы данных SQLite
Создание базы данных:
public static final String DATABASE_NAME = “Devices.db";
SQLiteDatabase db = openOrCreateDatabase (DATABASE_NAME, null);
Создание таблиц и индексов:
private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_VENDORS =
"CREATE TABLE " + DBScheme.Vendors.TABLE_NAME + " (" +
DBScheme.Vendors._ID + " INTEGER PRIMARY KEY," +
DBScheme.Vendors.COLUMN_NAME_ID + TEXT_TYPE + COMMA_SEP +
DBScheme.Vendors.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
DBScheme.Vendors.COLUMN_NAME_COUNTRY + TEXT_TYPE + COMMA_SEP + " )";
db.execSQL(SQL_CREATE_VENDORS );
db.execSQL("CREATE INDEX vendorsByNameIdx “+ "ON vendors (vendor_name)");
Базы данных SQLite
Запись информации в таблицу:
1-й способ:
db.execSQL("INSERT INTO vendors (name, country)"+
"VALUES (‘Samsung', South Korea)");
Так удобно делать если запросы не меняются в runtime.
2-й способ:
ContentValues values = new ContentValues();
values.put(DBScheme.Vendors.COLUMN_NAME_TITLE, “Samsung”);
values.put(DBScheme.Vendors.COLUMN_NAME_COUNTRY, “South Korea”);
long newRowId;
newRowId = db.insert( DBScheme.Vendors.TABLE_NAME, null, values);
Этот способ удобнее если запросы формируются динамически
Базы данных SQLite
Чтение информации из таблицы:
1-й способ:
String[ ] parms={“Samsung"};
Cursor result = db.rawQuery ("SELECT name, country FROM vendors WHERE
name=?“, parms);
Так удобно делать если запросы не меняются в runtime.
2-й способ:
String[ ] columns={“name“, “country”};
String[ ] parms={“Samsung"};
Cursor result=db.query(“vendors", columns, "name=?“, parms, null, null, null);
Последние 3 параметра: group by, having by, order by соответственно
Этот способ удобнее если запросы формируются динамически
Базы данных SQLite
Работа с полученным курсором:
Cursor result=
db.rawQuery("SELECT id, name, country FROM vendors");
cursor.moveToFirst();
while (!result.isAfterLast()) {
int id=result.getInt(0);
String name=result.getString(1);
String country=result.getString(2);
// do something useful with these
result.next();
}
result.close();
Важно! Не забывайте закрывать курсор после использования
Базы данных SQLite
Закрыть БД: db.close()
Удалить БД: deleteDatabase()
Что такое Content Provider
Content Provider – механизм, позволяющий нескольким
приложениям совместно пользоваться одним
источником данных (чаще всего БД, хотя и
необязательно)
Content Provider абстрагирует для приложения
конкретные детали хранилища данных, позволяя
обращаться к хранилищу унифицированным образом,
используя Uniform Resource Identifier
(http://tools.ietf.org/html/rfc3986)
Большинство стандартных приложений предоставляют
доступ к своим внутренним базам данных через
созданные ими Content Providers.
Использование Content Provider
Доступ к Content Provider осуществляется через объект
ContentResolver класса Context.
ContentResolver cr = getContentResolver();
Обычно провайдеры передают ссылку на хранилище данных
через CONTENT_URI property.
При этом существуют две формы URI:
- для запроса всего массива данных, совпадает с
CONTENT_URI
- для запроса конкретной записи CONTENT_URI/RowID
Использование Content Provider
Пример:
content://mleykin.hse.AddressBook/contacts/7
content:// - стандартное начало для адреса провайдера.
mleykin.hse.AddressBook– authority. Определяет провайдера
(аналогия с БД - имя базы).
contacts – это path. Определяет, какие данные от провайдера
нужны (таблица БД).
7 – это ID. Какая конкретно запись нужна (ID записи)
CONTENT_URI = content://mleykin.hse.AddressBook/contacts
Запрос данных через Content Provider
Запрос данных через объект ContentResolver осуществляется с
помощью метода query().
public final Cursor query (Uri uri, String[ ] projection, String selection,
String[ ] selectionArgs, String sortOrder)
Метод принимает:
• uri – content URI
• projection - массив столбцов таблицы, которые нужно
получить
• selection - условие where со занками ? в качестве параметров
• selectionArgs – аргументы, подставляемые в условие
• sortOrder – строка, задающая порядок сортировки результата
запроса
Запрос данных через Content Provider
// Return all rows
Cursor allRows =
getContentResolver().query(MyProvider.CONTENT_URI,
null, null, null, null);
// Return all columns for rows where column 3 equals a set value
and the rows are ordered by column 5.
String where = KEY_COL3 + “=” + requiredValue;
String order = KEY_COL5;
Cursor someRows =
getContentResolver().query(MyProvider.CONTENT_URI,
null, where, null, order);
Вставка через Content Provider
1-й способ:
// Create a new row of values to insert.
ContentValues newValues = new ContentValues();
// Assign values for each row.
newValues.put(COLUMN_NAME, newValue);
…
getContentResolver().insert(MyProvider.CONTENT_URI,
newValues);
2-й способ:
// Create a new row of values to insert.
ContentValues[] valueArray = new ContentValues[5];
// TODO: Create an array of new rows
int count =
getContentResolver().bulkInsert(MyProvider.CONTENT_URI,
valueArray);
Удаление через Content Provider
// Remove a specific row.
getContentResolver().delete(myRowUri, null, null);
// Remove the first five rows.
String where = “_id < 5”;
getContentResolver().delete(MyProvider.CONTENT_URI, where,
null);
Обновление через Content Provider
// Create a new row of values to insert.
ContentValues newValues = new ContentValues();
// Create a replacement map, specifying which columns you want to
// update, and what values to assign to each of them.
newValues.put(COLUMN_NAME, newValue);
// Apply to the first 5 rows.
String where = “_id < 5”;
getContentResolver().update(MyProvider.CONTENT_URI,
newValues, where, null);
Работа с файлами через Content Provider
Файлы представляются через URI. Чтобы добавить
файл в ContentProvider или получить доступ к
имеющемуся файлу:
try {
// Open an output stream using the new row’s URI.
OutputStream outStream = getContentResolver().openOutputStream(uri);
// Compress your bitmap and save it into your provider.
sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
}
catch (FileNotFoundException e) { }
Нативные провайдеры
- Browser – доступ к bookmarks, browser history, web searches.
- CallLog – доступ к call history
- Contacts – доступ к базе контактов
- MediaStore – доступ к мультимедиа-ресурсам
- Settings – доступ к настройкам устройства
Внимание! Чтобы работать с нативными провадйерами чаще всего
надо запросить у платформы разрешения, например для контактов:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Нативные провайдеры
// Get a cursor over every contact.
Cursor cursor = getContentResolver().query(Contacts.CONTENT_URI,
null, null, null, null);
// Let the activity manage the cursor lifecycle.
startManagingCursor(cursor);
// Use the convenience properties to get the index of the columns
int nameIdx = cursor.getColumnIndexOrThrow(Contacts.NAME);
int phoneIdx = cursor. getColumnIndexOrThrow(Contacts.NUMBER);
String[] result = new String[cursor.getCount()];
if (cursor.moveToFirst())
do {
// Extract the name.
String name = cursor.getString(nameIdx);
// Extract the phone number.
String phone = cursor.getString(phoneIdx);
result[cursor.getPosition()] = name + “ (“ + phone + “)”;
} while(cursor.moveToNext());
Создание собственного Content Provider
Чтобы создать собственный ContentProvider
необходимо унаследоваться от абстрактного класса
ContentProvider и переопределить метод onCreate()
public class MyProvider extends ContentProvider {
@Override
public boolean onCreate() {
// TODO: Construct the underlying database.
return true;
}
}
Создание собственного Content Provider
Также необходимо создать внутри класса переменную
CONTENT_URI, по которой будет осуществляться доступ к
ContentProvider.
Т.к. у каждого провайдера д.б. уникальный URI,
удобно использовать для URI имя пакета\приложения\вендора:
content://com.<CompanyName>.provider.<ApplicationName>/<DataPath>
Создание собственного Content Provider
Создаваемый ContentProvider должен поддерживать
две формы обращения: для получения всех данных
и для получения одной записи. Проще всего это сделать так:
public class MyProvider extends ContentProvider {
private static final String myURI = “content://com.paad.provider.myapp/items”;
public static final Uri CONTENT_URI = Uri.parse(myURI);
public boolean onCreate() {
// TODO: Construct the underlying database.
return true;
}
// Create the constants used to differentiate between the different URI requests.
private static final int ALLROWS = 1;
private static final int SINGLE_ROW = 2;
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(“com.paad.provider.myApp”, “items”, ALLROWS);
uriMatcher.addURI(“com.paad.provider.myApp”, “items/#”, SINGLE_ROW);
}
}
Создание собственного Content Provider
Переопределяем методы query(), insert(), delete(), update()
public class MyProvider extends ContentProvider {
public boolean onCreate() { }
public String getType(Uri url) { }
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) { }
public Uri insert(Uri _url, ContentValues _initialValues) { }
public int delete(Uri url, String where, String[] whereArgs) { }
public int update(Uri url, ContentValues values,
String where, String[] wArgs) { }
}
Создание собственного Content Provider
Переопределяем query()
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sort) {
// If this is a row query, limit the result set to the passed in row.
switch (uriMatcher.match(uri)) {
case SINGLE_ROW :
// TODO: Modify selection based on row id, where:
// rowNumber = uri.getPathSegments().get(1));
}
return null;
}
Создание собственного Content Provider
Переопределяем insert()
@Override
public Uri insert(Uri _uri, ContentValues _initialValues) {
long rowID = [ ... Add a new item ... ]
// Return a URI to the newly added item.
if (rowID > 0) {
return ContentUris.withAppendedId(CONTENT_URI, rowID);
}
throw new SQLException(“Failed to add new item into “ + _uri);
}
Создание собственного Content Provider
Переопределяем delete()
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
switch (uriMatcher.match(uri)) {
case ALLROWS:
case SINGLE_ROW:
default: throw new IllegalArgumentException(“Unsupported URI:” + uri);
}
}
Создание собственного Content Provider
Также надо определить MIME тип данных, с которым работает данный
провайдер:
@Override
public String getType(Uri _uri) {
switch (uriMatcher.match(_uri)) {
case ALLROWS: return “vnd.paad.cursor.dir/myprovidercontent”;
case SINGLE_ROW: return “vnd.paad.cursor.item/myprovidercontent”;
default: throw new IllegalArgumentException(“Unsupported URI: “ + _uri);
}
}
Создание собственного Content Provider
После создания надо зарегистрировать созданный
ContentProvider в AndroidManifest.xml
<provider android:name=”MyProvider”
android:authorities=”com.paad.provider.myapp”/>
Download