引用:
Android提供的数据持久化存储方式有以下几种。
1.Shared Preferences:以Key-Value形式存储数据
2.Internal Storage:数据文件存储在内存卡 3.External Storage:数据存储在外部设备,如SD卡等 4.SQLite Databases:SQLite存储方式 5.Network Connection:通过WebService等网络通信方式存储数据。
一、Shared Preferences
常用来存储应用中的用户偏好设置,例如应用的默认皮肤设置、记录用户上次登录信息等。数据的存储格式为Key-Value。
下面通过案例,记录用户信息来了解如何使用Shared Preferences。
介绍将使用到的Android SDK API:
SharedPreferences类:提供了一批读取、遍历数据的API。
Editor类:提供修改、保存数据API。
getSharedPreferences(String name, int mode):指定存储文件的文件名,并设置访问权限 getPreferences(int mode):如果你的Activity中只需要一个喜好文件,则可以不提供存储文件名,只需要设置访问权限 更多介绍可以访问:1、新建Android项目
项目名称Shared Preferences,主Activity名称为MainActivity。
2、设计主界面XML描述
[html] <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/name" /> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/name" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/age" /> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/age" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/save" android:onClick="save" /> </LinearLayout> <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" ><TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/name" /> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/name" /><TextView
android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/age" /> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/age" /><Button
android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/save" android:onClick="save" /></LinearLayout>界面效果:3、定义“保存”按钮的save事件处理方法
[java] package mr.jin.shared; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { private EditText nameEdit; private EditText ageEdit; private String USERINFO="userInfo"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); nameEdit = (EditText) findViewById(R.id.name);//应用打开后,即查找到姓名、年龄的文本框对象。 ageEdit = (EditText) findViewById(R.id.age); init(); } public void save(View v){ try{ SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE); Editor editor = perference.edit(); editor.putString("name", nameEdit.getText().toString()); editor.putString("age", ageEdit.getText().toString()); editor.commit();//未调用commit前,数据实际是没有存储进文件中的。 调用后,存储存储 Toast.makeText(this, R.string.success, Toast.LENGTH_LONG).show(); }catch(Exception e){ Toast.makeText(this, R.string.error, Toast.LENGTH_LONG).show(); } } /*第一次打开应用时,读取本地用户信息设置*/ public void init(){ SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE); nameEdit.setText(perference.getString("name", "")); ageEdit.setText(perference.getString("age", "")); } } package mr.jin.shared;import android.app.Activity;
import android.content.Context;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.Toast;public class MainActivity extends Activity {
private EditText nameEdit; private EditText ageEdit; private String USERINFO="userInfo"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); nameEdit = (EditText) findViewById(R.id.name);//应用打开后,即查找到姓名、年龄的文本框对象。 ageEdit = (EditText) findViewById(R.id.age);init();
} public void save(View v){ try{ SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE); Editor editor = perference.edit(); editor.putString("name", nameEdit.getText().toString()); editor.putString("age", ageEdit.getText().toString()); editor.commit();//未调用commit前,数据实际是没有存储进文件中的。 调用后,存储存储 Toast.makeText(this, R.string.success, Toast.LENGTH_LONG).show(); }catch(Exception e){ Toast.makeText(this, R.string.error, Toast.LENGTH_LONG).show(); } } /*第一次打开应用时,读取本地用户信息设置*/ public void init(){ SharedPreferences perference = getSharedPreferences(USERINFO, Context.MODE_PRIVATE); nameEdit.setText(perference.getString("name", "")); ageEdit.setText(perference.getString("age", "")); }} 4、部署应用第一次打开应用,两个输入框都为空。在输入信息后,点击保存。退出应用,再次打开应用,将显示之前保存的用户信息。
二、Internal Storage
可以将文件存储在内部存储设备,默认文件访问权限是私有的,除了当前应用,其他应用无法访问。当用户卸载您的应用程序,这些文件将被删除。
来看看Android SDK提供的文件存储权限:
Context.MODE_APPEND;//追加方式存储
Context.MODE_PRIVATE;//私有方式存储,其他应用无法访问Context.MODE_WORLD_READABLE;//允许其他应用读取数据Context.MODE_WORLD_WRITEABLE;//允许其他应用写入、读取数据 1.建立项目项目名称InternalStorage,主Activity类名称MainActivity。
2.定义界面及XML描述
print?<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="输入文字" /> <EditText android:minLines="3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/editText" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="保存" android:onClick="save" /> <TextView android:id="@+id/showText" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="显示保存的数据" android:onClick="showData" /> </LinearLayout> <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" ><TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="输入文字" /> <EditText android:minLines="3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/editText" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="保存" android:onClick="save" /> <TextView android:id="@+id/showText" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="显示保存的数据" android:onClick="showData" /></LinearLayout>3.定义“保存”按钮的save、“显示保存的数据”按钮的事件处理 [java] package mr.jin.internal; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { private EditText editText; private TextView showText; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); editText = (EditText) findViewById(R.id.editText); showText = (TextView) findViewById(R.id.showText); } public void save(View v){ String content = editText.getText().toString(); try { FileOutputStream outfile = openFileOutput("current_file", Context.MODE_PRIVATE); outfile.write(content.getBytes()); outfile.close(); Toast.makeText(this, "保存成功", 3000).show(); } catch (Exception e) { Toast.makeText(this, "保存失败", 3000).show(); e.printStackTrace(); } } public void showData(View v){ try { FileInputStream showfile = openFileInput("current_file"); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = 0; while( (len=showfile.read(data)) != -1){ out.write(data, 0, len); } String content = new String(out.toByteArray()); showText.setText(content); Toast.makeText(this, "显示成功", 3000).show(); } catch (Exception e) { Toast.makeText(this, "显示失败", 3000).show(); e.printStackTrace(); } } } package mr.jin.internal;import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;import java.io.FileOutputStream;import android.app.Activity;
import android.content.Context;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity {
private EditText editText; private TextView showText; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); editText = (EditText) findViewById(R.id.editText); showText = (TextView) findViewById(R.id.showText); } public void save(View v){ String content = editText.getText().toString(); try { FileOutputStream outfile = openFileOutput("current_file", Context.MODE_PRIVATE); outfile.write(content.getBytes()); outfile.close(); Toast.makeText(this, "保存成功", 3000).show(); } catch (Exception e) { Toast.makeText(this, "保存失败", 3000).show(); e.printStackTrace(); } } public void showData(View v){ try { FileInputStream showfile = openFileInput("current_file"); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = 0; while( (len=showfile.read(data)) != -1){ out.write(data, 0, len); } String content = new String(out.toByteArray()); showText.setText(content); Toast.makeText(this, "显示成功", 3000).show(); } catch (Exception e) { Toast.makeText(this, "显示失败", 3000).show(); e.printStackTrace(); } }}4.部署测试。
三、External Storage
扩展存储,例如常见扩展存储有SD卡,可以将大容量的数据存储在外部存储中。
因为SD卡是可以由用户自由装载、卸载的,所以在使用SD卡上的文件之前,应该先检测设备是否已经装载成功。
通过判断Environment.getExternalStorageState()的返回值,可以知道目前SD卡的状态。
1、访问SD卡上文件
a.如果使用API级别大于等于8,可以使用getExternalFilesDir(String type),参数要求提供一个子目录名称,若传递null即为根目录,返回指定目录路径的File对象。
这里手册上建议使用有意义的子目录名称,便于Android媒体扫描器,正确的将文件分类。
[java] public class Environment {
public static String DIRECTORY_MUSIC = "Music"; //音频文件 public static String DIRECTORY_PODCASTS = "Podcasts"; //广播 public static String DIRECTORY_RINGTONES = "Ringtones"; //铃声 public static String DIRECTORY_ALARMS = "Alarms"; //警报 public static String DIRECTORY_NOTIFICATIONS = "Notifications"; //通知 public static String DIRECTORY_PICTURES = "Pictures"; //图片 public static String DIRECTORY_MOVIES = "Movies"; //电影 public static String DIRECTORY_DOWNLOADS = "Download"; //下载 public static String DIRECTORY_DCIM = "DCIM"; //照片 //...不完整的Environment类内容 } public class Environment { public static String DIRECTORY_MUSIC = "Music"; //音频文件 public static String DIRECTORY_PODCASTS = "Podcasts"; //广播 public static String DIRECTORY_RINGTONES = "Ringtones"; //铃声 public static String DIRECTORY_ALARMS = "Alarms"; //警报 public static String DIRECTORY_NOTIFICATIONS = "Notifications"; //通知 public static String DIRECTORY_PICTURES = "Pictures"; //图片 public static String DIRECTORY_MOVIES = "Movies"; //电影 public static String DIRECTORY_DOWNLOADS = "Download"; //下载 public static String DIRECTORY_DCIM = "DCIM"; //照片 //...不完整的Environment类内容}b.API级别小于等于7,可以使用getExternalStorageDirectory(),将返回文件路径为/Android/data/<package_name>/files/的File对象,这里的<package_name>就是AndroidManifest.xml中<manifest>标签中定义package。 这两种方法创建的文件,在应用被卸载时,文件也随之删除。
2、如果不希望创建的文件在应用卸载后被删除,可以使用下面的方法
以共享文件的方式存储,任何应用都将可以访问这些文件。
a.API大于等于8,getExternalStoragePublicDirectory (String type),参数与getExternalFilesDir(String type)中的参数一样,指定子目录。
b.API小于等于7,getExternalStorageDirectory(),返回外部存储的根目录的File对象。然后将文件存储在:
Music/ - 媒体扫描仪划分为用户的音乐在这里发现的所有媒体。
Podcasts/ - 媒体扫描仪的分类在这里找到一个podcast的所有媒体。Ringtones/ - 媒体扫描器分类作为铃声,在这里发现所有的媒体。Alarms/ - 媒体扫描仪发出报警声,这里发现的所有媒体分类。Notifications/ - 媒体扫描仪的分类作为通知的声音在这里发现的所有媒体。Pictures/ - 所有照片(不包括那些用相机拍摄)。Movies/ - 所有电影(不包括用摄像机拍摄的)。Download/ - 杂项下载。
四、SQLite存储
Android提供了对SQLite全面支持,无需考虑数据库连接、连接池等问题。
只需要集成SQLiteOpenHelper类,它提供了访问数据库、事务等API。
[java] package mr.jin.service;
import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DBOpenHelper extends SQLiteOpenHelper { public DBOpenHelper(Context context) { //第一个参数:传递上下文对象 //第二个参数:数据库保存的文件名 //第三个参数:null使用默认的创建游标对象工厂 //第四个参数:最重要,表示数据库版本号,最小值1。每次运行应用前 // 会与当前应用的数据库版本做比较,如果大于当前版本号 // 将调用onUpgrade方法。 super(context, "dbfile.db", null, 1); } @Override public void onCreate(SQLiteDatabase db) {//只在第一次运行应用时调用,这里可以运行创建数据库结构的代码 db.execSQL("CREATE TABLE person(personid integer primary key autoincrement, name varchar(20))"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//只在数据库版本发生改变时调用 db.execSQL("ALTER TABLE person ADD amount integer NULL"); } } package mr.jin.service;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DBOpenHelper extends SQLiteOpenHelper {
public DBOpenHelper(Context context) {
//第一个参数:传递上下文对象 //第二个参数:数据库保存的文件名 //第三个参数:null使用默认的创建游标对象工厂 //第四个参数:最重要,表示数据库版本号,最小值1。每次运行应用前 // 会与当前应用的数据库版本做比较,如果大于当前版本号 // 将调用onUpgrade方法。 super(context, "dbfile.db", null, 1); }@Override
public void onCreate(SQLiteDatabase db) {//只在第一次运行应用时调用,这里可以运行创建数据库结构的代码 db.execSQL("CREATE TABLE person(personid integer primary key autoincrement, name varchar(20))"); }@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//只在数据库版本发生改变时调用 db.execSQL("ALTER TABLE person ADD amount integer NULL"); }}
SQLiteOpenHelper提供了两个API来获得数据库连接对象SQLiteDatabase: getWritableDatabase():返回可读、写对象 getReadableDatabase():返回可读、写对象。仅当无法写时,返回只读对象。 具体一些操作数据库的方法,可以参看SQLiteDatabase API手册,提供的方法已经足够多了。