Strategies for Landing an Oracle DBA Job as a Fresher
Android Data Persistence
1. Data
Persistence
in
Android
Jussi
Pohjolainen
Tampere
University
of
Applied
Sciences
2. Contents
• Overview
• About
State
InformaAon
• Preferences
• Using
files
• Using
databases
• Accessing
Content
Providers
3. 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
4. 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
5. 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!
6. Store
@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
String text = tv.getText().toString();
savedInstanceState.putString("someKey", text);
super.onSaveInstanceState(savedInstanceState);
}
8. 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)
9. 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.
10. 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();
}
}
11. 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
aer
that
12. StaAc
files
• You
can
save
staAc
files
into
res/raw
directory
• Accessing
using
openRawResource(R.raw.<filename>)
• Returns
InputStream
• Cannot
write
to
data
14. Reading
MODE_WORLD_READABLE
file
• When
reading
public
file,
use
FileInputStream
(vs.
openFileInput)
• Give
full
path:
/data/data/<package>/files
15. 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.
16. 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();
}
}
18. 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();
}
}
19. 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
20. 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);
}
}
21. // 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);
}
}
}
23. 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
24. 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
26. 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
(fih)
– content://fi.pohjolainen_jussi.provider.myapp/items/5
28. 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);
}
}
29. 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) {...}
}
30. 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
31. 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);
}
}
32. 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;
}
}