在Android中,实现数据持久化主要有四种方式:Preferences,文件I/O,SQLite数据库,ContentProvider组件。
这里面讲的也很好:http://www.cnblogs.com/weixing/p/3243115.html
Preferences
Preferences是一种轻量级的数据存储机制,他将一些简单的数据类型的数据,包括boolean类型,int类型,float类型,long类型以及String类型的数据,以键值对的形式存储在应用程序的私有Preferences目录(/data/data/<包名>/shared_prefs/)中,这种Preferences机制广泛应用于存储应用程序中的配置信息。
SharedPreferences sharedPreferences = getSharedPreferences("ljq", Context.MODE_PRIVATE);//如果ljq不存在,则会自动新建
Editor editor = sharedPreferences.edit();//获取编辑器,然后就可以编辑它
editor.putString("name", "cjw");
editor.putInt("age", 4);
editor.commit();//提交修改
写入数据:
sPrefs = PreferenceManager.getDefaultSharedPreferences(context);
sPrefs.edit().putInt(SCREEN_COUNT, count).commit();
查看Preferences中的数据的方法有两种:
第一种是使用adb命令查看;
第二是使用DDMS——>FileExplorer在目录/data/data/<包名>/shared_prefs/中Preferences导出来查看。
如何访问其他应用中的Preference?
public void testAccessPreference2() throws Exception{
Context context = this.getContext().createPackageContext("com.ljq.activity",
Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sharedPreferences = context.getSharedPreferences("ljq123",
Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 1);
Log.i(TAG, name + " : " +age);
}
2)文件I/O
1.使用内部存储器
创建:
- Call openFileOutput()
- Write to the file with write().
- Close the stream with close().
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
- Call openFileInput()
- and pass it the name of the file to read. This returns a FileInputStream.
- Read bytes from the file with read().
- Then close the stream with close().
res/raw/
directory. You can open it with
openRawResource()
为了读取或写入外部存储文件,您的应用程序必须获得 READ_EXTERNAL_STORAGE 或WRITE_EXTERNAL_STORAGE系统权限。例如:
<manifest ... >
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
如果你需要同时读取和写入文件,那么你需要请求只有 WRITE_EXTERNAL_STORAGE权限,因为它隐含地要求读访问也是如此。
4.4之后私有的读取就不需要申明
2.Before you do any work with the external storage, you should always call getExternalStorageState() to check whether the media is available./* Checks if external storage is available for read and write 可读可写的检查*/
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();// Environment提供环境变量的访问
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read只读的检查 */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
...
</manifest>
调用
getExternalCacheDir()方法,
类似
ContextCompat.getExternalFilesDirs()
Android平台主要通过java.io.FileInputStream和java.io.FileOutputStream这两个类来实现对文件的读写,java.io.File类则用来构造一个具体指向某个文件或者文件夹的对象。
需要注意的是:每个应用程序所在的包都会有一个私有的存储数据的目录,只有属于这个包中的应用程序才有写入的权限,每个包中应用程序的私有数据目录位于 Android系统中的绝对路径/data/data/<package>/目录中,除了私有目录,应用程序还拥有/sdcard目录即 Android设备上的SD卡的写入权限。文件系统中其他的系统目录,第三方应用程序都是不可写的。
在我们RUI中,下载推荐应用时,就是在SD卡中建立一个目录,将下载的apk放入该目录中,具体的实现可以查看com.rui.mid.launcher.service.download中的FileUtil.java文件。在该文件中有一个changeMode方法改变文件的权限(可读,可写,可执行),就是为了能让系统调用该apk,实现应用的安装。
3)SQLite数据库
当应用程序需要处理的数据量比较大时,为了更加合理地存储、管理、查询数据,我们往往使用关系数据库来存储数据。Android平台为开发者提供了SQLite数据库相关的API来实现对数据库操作的支持,开发人员可以很方便的使用这些API来对SQLite数据库进行创建、修改及查询等操作。Android系统的很多用户数据,如联系人信息,通话记录,短信息等,都是存储在SQLite数据库当中的,所
以利用操作SQLite数据库的API可以同样方便的访问和修改这些数据。
在实际的应用程序编写中,为了更好的对SQlite数据的创建,打开,更改进行管理,往往会编写一个SQLiteOpenHelper的数据库辅助类来帮助我们创建和打开数据库。可以查考博客http://blog.csdn.net/rhljiayou/article/details/7085347
源码:
package com.example.usingpreference;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText parem1;
private EditText parem2;
private Button save;
private Button show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parem1 = (EditText) this.findViewById(R.id.editText1);
parem2 = (EditText) this.findViewById(R.id.editText2);
save = (Button) this.findViewById(R.id.button1);
show = (Button) this.findViewById(R.id.button2);
// 进入应用使用直接显示上次保存的输入
SharedPreferences sharedPreferences = getSharedPreferences(
"chenjianwu", MODE_PRIVATE);
parem1.setText(sharedPreferences.getString("name", ""));
parem2.setText(Integer.toString(sharedPreferences.getInt("age", 1)));
// 取缓存数据(/data/data/cache)追加显示
String appendCache = null;
try {
appendCache = getCache("cjw");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
parem1.append("+缓存追加:" + appendCache);
// 读取内部存储器数据,追加显示
String appendInternal = null;
try {
appendInternal = getInternal("hello_file");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
parem1.append("+读取内部存储器追加:"+appendInternal);
}
/**
* 按钮监听事件,保存数据和显示数据
* @param view
* @throws IOException
*/
public void listener(View view) throws IOException {
Button button = (Button) view;
String name = parem1.getText().toString().trim();
int age = Integer.parseInt(parem2.getText().toString().trim());
SharedPreferences preferences = getSharedPreferences("chenjianwu",
MODE_PRIVATE);
switch (button.getId()) {
case R.id.button1:
Editor editor = preferences.edit();// 声明编辑器,编辑内容后commit()来提交编辑结果
editor.putString("name", name);
editor.putInt("age", age);
editor.commit();
// 使用内部存储器保存文件
String FILENAME = "hello_file";
String string = "hello world 你好!";
FileOutputStream fos = openFileOutput(FILENAME,
Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
// 使用缓存文件保存数据
File catchFile = new File(getCacheDir(), "cjw");// getCacheDir()返回cache的绝对路劲
FileOutputStream catchoutput = new FileOutputStream(catchFile);
catchoutput.write(string.getBytes());
break;
case R.id.button2:
parem1.setText(preferences.getString("name", ""));
parem2.setText(Integer.toString(preferences.getInt("age", 1)));
default:
break;
}
}
/**
* 读取缓存文件内容(/data/data/cache)
*
* @param filename
* 文件名
* @return 返回Sting类型
* @throws IOException
*/
public String getCache(String filename) throws IOException {
File f = new File(getCacheDir(), filename);
FileInputStream fis = new FileInputStream(f);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = -1;
while ((len = fis.read(data)) != -1) {
baos.write(data, 0, len);
}
return new String(baos.toByteArray());
}
/**
* 获取内部存储器文件内容(/data/data/files)
*
* @param filename
* @return
* @throws IOException
*/
public String getInternal(String filename) throws IOException {
FileInputStream fis = openFileInput(filename);//调用openFileInput()来获取内部存储器输入流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = -1;
while ((len = fis.read(data)) != -1) {
baos.write(data, 0, len);
}
return new String(baos.toByteArray());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="参数1:" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:layout_marginTop="64dp"
android:text="参数2:" />
<EditText
android:id="@+id/editText1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/textView2"
android:layout_toRightOf="@+id/textView2"
android:ems="10" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/editText2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/textView1"
android:layout_toRightOf="@+id/textView1"
android:ems="10" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView2"
android:layout_below="@+id/editText1"
android:layout_marginTop="129dp"
android:text="保存"
android:onClick="listener"/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/button1"
android:layout_alignBottom="@+id/button1"
android:layout_alignRight="@+id/editText1"
android:text="显示"
android:onClick="listener" />
</RelativeLayout>