简介
数据持久化是指将内存中的瞬时数据保存到存储设备中, 保证即使在手机或电脑关机的情况下数据也不会丢失.
Android系统中主要提供了三种持久化方式, 即文件存储, SharedPreferences 存储和数据库存储. 此外, 还可以将数据保存在SD卡中, 不过使用前面三种方式更简单也更安全.
文件存储
这种方式不会对存储的内容进行任何的格式化处理, 所有数据都原封不动保存到文件当中. 因而比较适合用于存储一些简单的文本数据或二进制数据.
将数据存储到文件中
Context 类中提供了一个openFileOutput()
方法, 用于将数据存储到指定的文件中. 该方法接收两个参数, 第一个是文件名(不可以包含路径, 因为默认存储到/data/data/<packagename>/files/
目录下), 第二个是文件的操作模式. MODE_PRIVATE(默认, 指定同名文件时, 所写内容将会覆盖原文件中的内容) 和 MODE_APPEND(如果该文件存在就往文件里追加内容, 不存在就创建文件).
openFileOutput()
方法返回的是一个 FileOutputStream 对象, 得到这个对象后就可以用Java流的方式将数据写入到文件中了.
新建一个项目, 首先修改 activity_main , 定义一个 EditText .
然后修改 MainActivity :
public class MainActivity extends Activity {
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = (EditText) findViewById(R.id.edit);
}
@Override
protected void onDestroy() {
super.onDestroy();
String inputText = edit.getText().toString();
save(inputText);
}
private void save(String inputText) {
FileOutputStream out = null;
BufferedWriter writer = null;
try {
out = openFileOutput("data", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(inputText);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行程序. 活动销毁时会自动将输入的数据保存到data文件中. 怎么查看? Android Studio 中在工具栏有一个 green robot, ADM.
从文件中读取数据
Context 类还提供了一个openFileInput()
方法, 用于从文件中读取数据. 只接受一个参数, 即文件名. 系统会自动到/data/data/<packagename>/files/
目录下去加载这个文件, 并返回一个 FileInputStream 对象, 再通过Java流的方式就可以将数据读取出来了.
使上一个程序启动时EditText能够保留上次输入的内容.
修改 MainActivity :
public class MainActivity extends Activity {
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = (EditText) findViewById(R.id.edit);
String inputText = load();
//TextUtils.isEmpyty(): 传入字符等于null或者等于空串时, 返回true.
if (!TextUtils.isEmpty(inputText)) {
edit.setText(inputText);
edit.setSelection(inputText.length());//将光标移动到文本末尾
Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
String inputText = edit.getText().toString();
save(inputText);
}
private void save(String inputText) {
FileOutputStream out = null;
BufferedWriter writer = null;
try {
out = openFileOutput("data", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(inputText);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String load() {
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
in = openFileInput("data");
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
content.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return content.toString();
}
}
SharedPreferences 存储
不同于文件存储, SharedPreferences 使用键值对的形式来存储数据. 通过键可以把相应的值取出来. 文件以 XML 格式对数据进行管理, 存储到/data/data/<packagename>/shared_prefs/
目录下.
将数据存储到 SharedPreferences 中
首先, 要获取到 SharedPreferences 对象. Android中主要有三种方法:
* Context类中的 getSharedPreferences()
方法.
* 该方法需要两个参数, 第一个是文件名, 第二个指定操作模式, 可选 MODE_PRIVATE
(默认, 也可直接传入0, 表示只有当前程序才可以读取该文件)和 MODE_MULTI_PROCESS
(一般用于会有多个进程中对同一个文件进行读写的情况).
* Activity类中的 getPreferences()
方法.
* 只接收一个参数, 即操作模式. 会自动将当前活动的类名作为文件名.
* PreferenceManager类中的 getDefaultSharedPreferences()
方法.
* 静态方法, 只接受一个Context参数, 使用当前程序的包名作为前缀来命名文件.
得到 SharedPreferences 对象之后, 就可以向 SP 文件中存储数据了. 分为3步:
1, 调用 SharedPreferences 对象的 edit()
方法来获取一个 SharedPreferences.Editor 对象.
2, 向 SharedPreferences.Editor 对象添加数据. 利用put[Type]()
方法.
3, 调用 commit()
方法将添加的数据提交, 完成存储操作.
新建一个项目, 在 activity_main.xml 文件中放置一个按钮.
然后修改 MainActivity 代码:
public class MainActivity extends Activity {
private Button saveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
saveData = (Button) findViewById(R.id.save_data);
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor =
getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("name", "Eric");
editor.putInt("age", 23);
editor.putBoolean("married", false);
editor.commit();
}
});
}
}
从 SharedPreferences 中读取数据
通过get[Type]()
方法来读取数据. 这一系列方法接收两个参数, 第一个是键, 第二个是默认值, 即根据键找不到值时返回的值.
修改activity_main.xml, 再添加一个按钮, 用于读取数据.
然后修改 MainActivity 的代码, 为刚才定义的按钮添加点击事件:
restoreData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences preferences = getSharedPreferences("data", MODE_PRIVATE);
String name = preferences.getString("name", "");
int age = preferences.getInt("age", 0);
boolean married = preferences.getBoolean("married", false);
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "age is " + age);
Log.d("MainActivity", "married is " + married);
}
});
实现记住密码功能
修改上一章 BroadcastBP 项目的代码.
修改login.xml:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="1">
<TableRow>
<TextView
android:layout_height="wrap_content"
android:text="Account:" />
<EditText
android:id="@+id/account"
android:layout_height="wrap_content"
android:hint="Input your account" />
</TableRow>
<TableRow>
<TextView
android:layout_height="wrap_content"
android:text="Password:" />
<EditText
android:id="@+id/password"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</TableRow>
<TableRow>
<CheckBox
android:id="@+id/remember_pass"
android:layout_height="wrap_content" />
<TextView
android:layout_height="wrap_content"
android:text="Remember password" />
</TableRow>
<TableRow>
<Button
android:id="@+id/login"
android:layout_height="wrap_content"
android:layout_span="2"
android:text="Login" />
</TableRow>
</TableLayout>
然后修改 MainActivity :
public class LoginActivity extends BaseActivity {
private SharedPreferences pref;
private SharedPreferences.Editor editor;
private EditText accountEdit;
private EditText passwordEdit;
private Button login;
private CheckBox rememberPass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
pref = PreferenceManager.getDefaultSharedPreferences(this);
accountEdit = (EditText) findViewById(R.id.account);
passwordEdit = (EditText) findViewById(R.id.password);
login = (Button) findViewById(R.id.login);
rememberPass = (CheckBox) findViewById(R.id.remember_pass);
boolean isRemember = pref.getBoolean("remember_password", false);
if (isRemember) {
//将账号和密码都设置到文本框中
String account = pref.getString("account", "");
String password = pref.getString("password", "");
accountEdit.setText(account);
passwordEdit.setText(password);
rememberPass.setChecked(true);
}
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String account = accountEdit.getText().toString();
String password = passwordEdit.getText().toString();
if (account.equals("admin") && password.equals("123456")) {
editor = pref.edit();
if (rememberPass.isChecked()) {
editor.putBoolean("remember_password", true);
editor.putString("account", account);
editor.putString("password", password);
} else {
editor.clear();
}
editor.commit();
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
} else {
Toast.makeText(LoginActivity.this,
"account or password is invalid", Toast.LENGTH_SHORT).show();
}
}
});
}
}