Вы находитесь на странице: 1из 16

Android Persistence with preferences and

files - Tutorial
Lars Vogel
Version 2.7
Copyright 2010, 2011, 2012 Lars Vogel
15.10.2012
Revision History

Revision 0.1

05.09.2010

Lars
Vogel

Created

Revision 0.2 - 2.7

21.09.2010 - 15.10.2012

Lars
Vogel

bugfixes and enhancements

File based persistence in Android


This tutorial describes how to save key-value pairs using the preference
API in Android. It also explains how to read and write files in Android. It is
based on Eclipse 3.7, Java 1.6 and Android 4.1 (Ice Cream Sandwich).

Table of Contents
1. Android File Based Persistence
1.1. Methods of persistence
1.2. Internal vs. external storage
1.3. Application on external storage
2. Preferences
2.1. API
2.2. Preference Values
2.3. PreferenceFragment
2.4. Preference Listener

3. Tutorial: Prerequirements
4. Tutorial: Preferences
4.1. Using preferences
4.2. Run
5. Android File API
5.1. Overview
5.2. How to access a shared file
5.3. External storage
6. Thank you
7. Questions and Discussion
8. Links and Literature
8.1. Source Code
8.2. Android Resources
8.3. vogella Resources

1. Android File Based Persistence


1.1. Methods of persistence
Android allows to store local data as files. Android uses file based storage
for handling application settings (Preferences) and instances of the SQLite
database.
For each application the Android system creates
a data/data/package.of.the.application directory.
Files are saved in the files folder and application settings are saved as
XML files in the shared_prefs folder.
If your application creates an SQLite database this database is saved in the
main application directory under thedatabases folder.
The following screenshot shows a filesystem which contains file, cache files
and preferences.

Only the application can write into its application directory. It can create
additional sub-directories in this application directory. For these subdirectories, the application can grant read or write permissions for other
applications.

1.2. Internal vs. external storage


Android has internal storage and external storage. External storage is not
private and may not always be available.

1.3. Application on external storage


As of Android 8 SDK level it is possible to define that the application can or
should be placed on external storage. For this set
the android:installLocation to preferExternal or auto.
In this case certain application components may be stored on an encrypted
external mount point. Database and other private data will still be stored in
the internal storage system.

2. Preferences
2.1. API
Android supports the usage of Preferences for persisting key-values pairs
in the Android file system.
The definition of Preferences can be done via an XML resource.

The PreferenceManager gives access to the preference values. The following


code shows how to access your default preferences.
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

Values can get accessed via the key of the preference setting.
String username = preferences.getString("username", "n/a");

To create or change preferences you have to call the edit() method on


the SharedPreferences object. Once you have changed the value you have to
call the commit() method to apply your changes.
Editor edit = preferences.edit();
edit.putString("username", "new_value_for_user");
edit.commit();

2.2. Preference Values


Android allows to create XML fileswhich describes the preferences which
should be entered. From this XML file the user interface is automatically
generated and the values are stored automatically by Android.
To create such a file, select File New Android Android XML
File and select the Preference as Resource Type.

2.3. PreferenceFragment
Android provides the PreferenceFragment class which simplifies the creation
of an user interface for maintaining preference values. This fragment can
load an XML preference definition file via the
methodaddPreferencesFromResource().

2.4. Preference Listener

You can listen to changes in the preferences via


the registerOnSharedPreferenceChangeListener()method on SharedPreferences.
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(this);

// Instance field for listener


listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// Your Implementation
}
};

prefs.registerOnSharedPreferenceChangeListener(listener);

One watch out is that SharedPreferences keeps listeners in


a WeakHashMap hence listener may be recycled if your code does not hold a
reference to it. .

3. Tutorial: Prerequirements
The following tutorial is based on the "de.vogella.android.socialapp"
example from Android ActionBar Tutorial .

4. Tutorial: Preferences
4.1. Using preferences
We will continue using the example project "de.vogella.android.social".
Create an Android XML resource called preferences.xml of
the PreferenceScreen type.

Open the file via right-click and Open with Android XML Resource Editor.
Press Add, add a PreferenceCategoryand add two preferences of
type EditTextPreferences. They should be called User and Password.

You can also enter values for other properties of


inputMethod.

EditTextField,

e.g. the

Add the following attribute to the XML definition of your password field to
make the input quoted with *.

android:inputType="textPassword"

Create the class MyPreferencesActivity which extends PreferenceActivity.


This activity will load thepreference.xml file and will allow the user to change
the values.
package de.vogella.android.socialapp;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class MyPreferencesActivity extends PreferenceActivity {


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}

To make this class available as an activity for Android you need to register it
in your AndroidManifest.xml file. SelectAndroidManifest.xml and
the Application tab. Scroll to the bottom of the view and add your
new activity via the Addbutton.

To make use of our new preference activity and the preference values we
adjust the "OverviewActivity". The first button will show the current values of
the preferences via a Toast and the second button will revert the maintained
user name to demonstrate how you could change the preferences via code.
package de.vogella.android.socialapp;

import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class OverviewActivity extends Activity {


SharedPreferences preferences;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.Button01);
// Initialize preferences
preferences = PreferenceManager.getDefaultSharedPreferences(this);

button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {

String username = preferences.getString("username", "n/a");


String password = preferences.getString("password", "n/a");
showPrefs(username, password);
}
});

Button buttonChangePreferences = (Button) findViewById(R.id.Button02);


buttonChangePreferences.setOnClickListener(new OnClickListener() {
public void onClick(View v) {

updatePreferenceValue();
}
});
}

private void showPrefs(String username, String password){


Toast.makeText(OverviewActivity.this,
"Input: " + username + " and password: "
+ password, Toast.LENGTH_LONG).show();

private void updatePreferenceValue(){


Editor edit = preferences.edit();
String username = preferences.getString("username", "n/a");
// We will just revert the current user name and save again
StringBuffer buffer = new StringBuffer();
for (int i = username.length() - 1; i >= 0; i--) {
buffer.append(username.charAt(i));
}
edit.putString("username", buffer.toString());
edit.commit();

// A toast is a view containing a quick little message for the


// user. We give a little feedback
Toast.makeText(OverviewActivity.this,
"Reverted string sequence of user name.",
Toast.LENGTH_LONG).show();
}

To open the new preference activity we will use


the onOptionsItemSelected() method. Even though we currently have only
one option in our menu we use a switch to be ready for several new menu
entries. To see the current values of the preferences we define a button and
use the class PreferenceManager to get the sharedPreferences.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mainmenu, menu);
return true;
}

// This method is called once the menu is selected


@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// We have only one menu option
case R.id.preferences:
// Launch Preference activity
Intent i = new Intent(OverviewActivity.this, MyPreferencesActivity.class);
startActivity(i);
// Some feedback to the user
Toast.makeText(OverviewActivity.this, "Enter your user credentials.",
Toast.LENGTH_LONG).show();

break;

}
return true;
}

4.2. Run
Run your application. Select from your ActionBar the Preference menu
entry. You should be able to enter your user settings then press the back
hardware button to return to your main activity. The saved values should be
displayed in a small message windows (Toast) if you press your first button.
If you press the second button the username should be reversed.

5. Android File API


5.1. Overview
Access to the file system is performed via the standard java.io classes.
Android provides also helper classes for creating and accessing new files
and directories. For example thegetDir(String, int) method would create or
access a directory. The openFileInput(String s) method would open a file
for input and openFileOutput(String s, int) would create a file.
int specifies the permissions which are:
MODE_PRIVATE - No access for other applications
MODE_WORLD_READABLE - Read access for other applications
MODE_WORLD_WRITABLE - Write access for other applications
MODE_WORLD_READABLE | MODE_WORLD_WRITABLE - Read /
Write access
The following example shows the API usage.
private void writeFileToInternalStorage() {
String eol = System.getProperty("line.separator");
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(openFileOutput("myfile",
MODE_WORLD_WRITEABLE)));
writer.write("This is a test1." + eol);
writer.write("This is a test2." + eol);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {

try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void readFileFromInternalStorage() {
String eol = System.getProperty("line.separator");
BufferedReader input = null;
try {
input = new BufferedReader(new InputStreamReader(openFileInput("myfile")));
String line;
StringBuffer buffer = new StringBuffer();
while ((line = input.readLine()) != null) {
buffer.append(line + eol);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

5.2. How to access a shared file

Another application can access a file, which has been created with
the MODE_WORLD_READABLE model. For this, it need to knows the package and
file name. The following example shows this.
FileInputStream openFileInput = createPackageContext("the_package",
0).openFileInput("thefile");

5.3. External storage


Android supports also access to an external storage system e.g. the SD
card. All files and directories on the external storage system are readable
for all applications with the correct permission.
To read from external storage your application need to have
theandroid.permission.READ_EXTERNAL_STORAGE permission.
To write to the external storage system your application needs
theandroid.permission.WRITE_EXTERNAL_STORAGE permission. You get the path
to the external storage system via
the Environment.getExternalStorageDirectory() method.
Via the following method call you can check the state of the external
storage system. If the Android device is connected via USB to a computer,
a SD card which might be used for the external storage system is not
available.
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

The following shows an example for reading from the external storage
system.
private void readFileFromSDCard() {
File directory = Environment.getExternalStorageDirectory();
// Assumes that a file article.rss is available on the SD card
File file = new File(directory + "/article.rss");

if (!file.exists()) {
throw new RuntimeException("File not found");
}
Log.e("Testing", "Starting to read");
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

6. Thank you

Вам также может понравиться