32
Data Persistence in Android Jussi Pohjolainen Tampere University of Applied Sciences

Android Data Persistence

Embed Size (px)

Citation preview

Page 1: Android Data Persistence

Data  Persistence  in  Android  

Jussi  Pohjolainen  Tampere  University  of  Applied  Sciences  

Page 2: Android Data Persistence

Contents  

•  Overview  •  About  State  InformaAon  •  Preferences  •  Using  files  •  Using  databases  •  Accessing  Content  Providers  

Page 3: Android Data Persistence

Overview  of  Data  Storing  

•  App  data  is  private  to  the  applicaAon  •  Several  mechanism  –  State  Storage:  Ram  memory!  

•  Mechanism  for  saving  acAvity’s  state  temporarily  –  Preferences  

•  Lightweight  mechanism  to  store  and  retrieve  key-­‐value  pairs  –  Files  

•  Open  and  save  files  on  the  device  or  removable  storage  –  SQLite  databases  

•  Databases  •  Content  provider  is  used  to  give  the  data  to  other  apps  

Page 4: Android Data Persistence

AcAvity  State:  Using  RAM  

•  AcAvity’s  state  informaAon  can  be  lost,  if  it’s  closed  – When  acAvity  is  no  longer  on  the  screen  and  it’s  closed  because  of  freeing  memory  

– When  screen  rota1on  is  changed,  the  acAvity  is  destroyed  and  opened  again  

 

Page 5: Android Data Persistence

How  to  Store  State  InformaAon  

•  Store  state:  – onSaveInstanceState(Bundle)

•  Read  state  – onRestoreInstanceState(Bundle)

•  This  will  store  data  only  temporarily:  for  app  life1me!  

•  Data  will  be  held  in  memory  un1l  the  app  is  closed!  

Page 6: Android Data Persistence

Store   @Override

public void onSaveInstanceState(Bundle savedInstanceState)

{

String text = tv.getText().toString();

savedInstanceState.putString("someKey", text);

super.onSaveInstanceState(savedInstanceState);

}

Page 7: Android Data Persistence

Load   @Override

protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState);

if (savedInstanceState != null) { String strValue = savedInstanceState.getString("someKey"); if (strValue != null) { textfield.setText(strValue); } }

}

Page 8: Android Data Persistence

Shared  Preferences:  Permanent  Storage  

•  Very  simple  way  of  share  small  amount  of  data  between  acAviAes  

•  Also  for  saving  the  state  of  the  app  •  Preferences  have  names,  so  apps  other  components  can  found  them  

•  Preferences  can  be  private  or  public  (world  readable,  writeable)  

Page 9: Android Data Persistence

How?  

•  SharedPreferences  provides  general  framework  for  saving  and  retrieving  

•  To  get  SharedPreferences,  use  –  getSharedPreferences(String name) –  Use  if  you  need  mulAple  preference  files  (idenAfied  by  name)  

–  getPreferences() –  Use  if  only  one  preferences  file  is  needed  

•  To  write  values,  call  edit() to  get  SharedPreferences.Editor  to  be  used  when  adding  values  to  file.  

Page 10: Android Data Persistence

Preferences  Example  

public class Calc extends Activity {

    public static final String PREFS_NAME = "MyPrefsFile";

    @Override

    protected void onCreate(Bundle state){

       super.onCreate(state);

       . . .

       // Restore preferences

       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);

       boolean silent = settings.getBoolean("silentMode", false);

    }

    @Override

    protected void onStop(){

       super.onStop();

      // We need an Editor object to make preference changes.

      // All objects are from android.context.Context

      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);

      SharedPreferences.Editor editor = settings.edit();

      editor.putBoolean("silentMode", mSilentMode);

      // Commit the edits!

      editor.commit();

    }

}

Page 11: Android Data Persistence

Files  •  It's  possible  to  store  files  on  the  mobile  device  or  on  a  

removable  storage  •  Current  applica1on  folder  only.  ExcepAon  thrown  

otherwise.  –  Modes:  MODE_PRIVATE,  MODE_WORLD_READABLE,  MODE_WORLD_WRITABLE  

•  Reading  –  openFileInput()

•  WriAng  –  openFileOutput()

•  Standard  Java  streams  a\er  that  

Page 12: Android Data Persistence

StaAc  files  

•  You  can  save  staAc  files  into  res/raw  directory  •  Accessing  using  openRawResource(R.raw.<filename>)

•  Returns  InputStream •  Cannot  write  to  data  

Page 13: Android Data Persistence

Files  // Write

String FILENAME = "hello_file";

String string = "hello world!";

FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);

fos.write(string.getBytes());

fos.close();

// Read

FileInputStream fis = openFileInput(FILENAME);

int byteChar;

while((byteChar = fis.read()) != -1)

{

System.out.println((char) byteChar);

}

fis.close()

Page 14: Android Data Persistence

Reading  MODE_WORLD_READABLE  file  

•  When  reading  public  file,  use  FileInputStream  (vs.  openFileInput)  

•  Give  full  path:  /data/data/<package>/files

Page 15: Android Data Persistence

SQLite  •  Support  for  SQlite  databases  – Database  is  private  to  the  applicaAon  that  creates  it  

•  SQLiteDatabase  object  represents  a  database  •  SQLiteOpenHelper  –  wrapper  for  database  acAons  

•  Android  SDK  has  a  tool  called  sqlite3  which  enables  you  to  browse  table  contents  using  sql  commands  and  command  line  

•  All  databases  are  stored  in  /data/data/<package_name>/databases folder  on  your  device.  

Page 16: Android Data Persistence

SQLiteDatabase:  Open   public void openDatabase() {

try {

db = this.openOrCreateDatabase("MyTestDatabase.db", MODE_PRIVATE, null);

db.execSQL("CREATE TABLE MYDATA(firstname TEXT, lastname TEXT)");

} catch (SQLiteException e) {

e.printStackTrace();

}

}

Page 17: Android Data Persistence

SQLiteDatabase:  Insert   public void insertRows() {

try {

db.execSQL("INSERT INTO MYDATA VALUES ('Jack', 'Smith')");

} catch (Exception e) {

e.printStackTrace();

}

}

Page 18: Android Data Persistence

SQLiteDatabase:  Read   public void readRows() {

try {

Cursor c = db.rawQuery("SELECT * FROM MYDATA", null);

String text = "";

c.moveToFirst();

for(int i=0; i<c.getCount(); i++) {

text += c.getString(0) + " " + c.getString(1);

c.moveToNext();

}

tv.setText(text);

} catch (Exception e) {

e.printStackTrace();

}

}

Page 19: Android Data Persistence

SQLiteOpenHelper  

•  Wraps  best  pracAce  pacern  for  creaAng,  opening  and  upgrading  databases  

•  You  hide  the  logic  used  to  decide  if  a  database  needs  to  be  created  or  upgraded  before  it's  opened  

Page 20: Android Data Persistence

Recommended  Way:  SQLiteOpenHelper  

public class DictionaryOpenHelper extends SQLiteOpenHelper {     private static final int DATABASE_VERSION = 2;     private static final String DICTIONARY_TABLE_NAME = "dictionary";     private static final String DICTIONARY_TABLE_CREATE =                 "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +                 KEY_WORD + " TEXT, " +                 KEY_DEFINITION + " TEXT);";     DictionaryOpenHelper(Context context) {         super(context, DATABASE_NAME, null, DATABASE_VERSION);     }     @Override     public void onCreate(SQLiteDatabase db) {         db.execSQL(DICTIONARY_TABLE_CREATE);     } }

Page 21: Android Data Persistence

// Example public class SQLiteExample extends Activity {

private MyDataHelper dbhelper;

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); dbhelper = new MyDataHelper(this); dbhelper.deleteAll(); dbhelper.insert("Jussi"); dbhelper.insert("Pekka"); dbhelper.insert("Tiina"); List<String> list = dbhelper.selectAll(); for(String object : list) { System.out.println(object); } } }

Page 22: Android Data Persistence

Remote  Shell  for  Databases  

Page 23: Android Data Persistence

Content  Providers  

•  The  recommended  way  of  sharing  data  in  Android  is  to  use  content  providers  

•  Generic  interface  for  data  •  Permission  control  and  accessing  using  URI  model  

•  NaAve  databases  available  as  Content  Providers  

•  Publishing  your  own  data  source,  other  apps  can  incorporate  your  database  

Page 24: Android Data Persistence

Content  Resolver  

•  ApplicaAon  context  has  Content  Resolver  which  you  can  use  to  access  data  – ContentResolver cr = getContentResolver();

•  For  accessing  other  databases,  you  need  a  URI  •  URI  is  arbitraty  String,  which  is  defined  in  manifest  file  

Page 25: Android Data Persistence

Usage  // Query

Cursor c = getContentResolver().query(URI, ..., ... ,...);

// Insert

getContentResolver().insert(URI, newValues);

// Delete

getContentResolver().delete(URIofTheRow, ...);

Page 26: Android Data Persistence

URIs  

•  Content  URIs  must  be  unique  between  providers.  

•  Use  your  package  name  •  General  form  –  content://com.<company>.provider.<app>/<data>

•  Example  for  querying  all  items  –  content://fi.pohjolainen_jussi.provider.myapp/items

•  Example  for  querying  single  item  (fi\h)  –  content://fi.pohjolainen_jussi.provider.myapp/items/5

Page 27: Android Data Persistence

Manifest  

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="fi.tamk"

android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".CallMe"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

<provider android:name=".Data"

android:authorities="fi.pohjolainen_jussi.provider.mycontentprovider"></provider>

</application>

<uses-sdk android:minSdkVersion="8" />

</manifest>

Page 28: Android Data Persistence

Accessing  Content  Provider  public class MyContentProvider extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

ContentResolver cr = getContentResolver();

Uri uri = Uri.parse("content://fi.pohjolainen_jussi.provider.mycontentprovider");

Cursor cursor = cr.query(uri, null, null, null, null);

}

}

Page 29: Android Data Persistence

Extend  Content  Provider  

public class MyContentProvider extends ContentProvider {

@Override

public int delete(Uri uri, String selection, String[] selectionArgs) {...}

@Override

public String getType(Uri uri) {...}

@Override

public Uri insert(Uri uri, ContentValues values) {...}

@Override

public boolean onCreate() {...}

@Override

public Cursor query(Uri uri, String[] projection, String selection,

String[] selectionArgs, String sortOrder) {...}

@Override

public int update(Uri uri, ContentValues values, String selection,

String[] selectionArgs) {...}

}

Page 30: Android Data Persistence

URLMatcher  

•  The  content  provider  can  give  different  results  depending  on  the  URI:  – content://fi.pohjolainen_jussi.provider.myapp/items

– content://fi.pohjolainen_jussi.provider.myapp/items/5

•  Use  UAlity  class  URLMatcher  to  differenAate  the  given  URIs  

Page 31: Android Data Persistence

Example  of  URIMatcher  public class Data extends ContentProvider {

@Override

public boolean onCreate() {

initializeUriMatcher();

return false;

}

...

// Differentiate between different URI requests

private static final int ALLROWS = 1;

private static final int SINGLE_ROW = 2;

// UriMatcher is utility class for aiding matching URIs in content providers

private UriMatcher uriMatcher;

private void initializeUriMatcher() {

// Root node for the URI Matcher

uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

// Add a URI to match, and the code to return when this URI is matched

uriMatcher.addURI("fi.pohjolainen_jussi.provider.mycontentprovider", "items", ALLROWS);

uriMatcher.addURI("fi.pohjolainen_jussi.provider.mycontentprovider", "items/#", SINGLE_ROW);

}

}

Page 32: Android Data Persistence

Example  of  URIMatcher  public class Data extends ContentProvider {

@Override

public boolean onCreate() {

initializeUriMatcher();

return false;

}

@Override

public Cursor query(Uri uri, String[] projection, String selection,

String[] selectionArgs, String sortOrder) {

switch(uriMatcher.match(uri)) {

case SINGLE_ROW:

String rowNumber = uri.getPathSegments().get(1);

// ..

break;

case ALLROWS:

//

break;

}

return null;

}

}