数据持久化就是指将内存中的瞬时数据保存到存储设备中,保证即使设备在重启之后,数据仍然不会丢失。 持久化技术提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换。
Android系统主要提供了三种方式用于实现数据持久化功能:文件存储、SharedPreference存储、以及数据库存储。
一、文件存储
二、SharedPreference存储
不同于文件存储,SharedPreference是使用键值对的方式来存储数据的。每存储一条数据,都需要SharedPreference给这条数据一个对应的键值,然后在需要读取数据的时候也是根据键值来取出相应的数据。由此可见,当需要存储的数据结构比较复杂的时候,SharedPreference存储的便捷性和可用性优点就体现出来了。
2.1 使用SharedPreferences存储数据
Android中主要提供了3种方法用于得到SharedPreferences对象:
1.Context类中的getSharedPreferences()方法
此方法接收两个参数,第一个参数用于指定SharedPreferences文件的名称,如果指定文件不存在则新建一个。SharedPreferences文件默认存放在/data/data/<package name>/shared_prefs/目录下。第二个参数用于指定操作模式,默认的操作模式是MODE_PRIVATE,和传入0一样。目前也只有这一种模式可选,MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE这两种模式在Android 4.2版本中被废弃,MODE_MULTI_PROCESS模式在Android 6.0中被废弃。
2.Activity类中的getPreferences()方法
这个方法和Context中的getSharedPreference()方法很相似,不过它只接受一个操作模式参数,因为使用这个方法时会自动将当前活动类名作为SharedPreferences的文件名。
3.PreferenceManager类中的getDefaultSharedPreferences()方法
这是一个静态方法,它接受一个Context参数,并自动使用当前程序包名作为前缀来命名SharedPreferences文件。
在得到SharedPreferences对象后,就可以向SharedPreferences文件中存储数据了。向SharedPreferences文件中存储数据需要三步:
(1)调用SharedPreferences对象的edit()方法来获取一个SharedPreferences.Editor对象。
(2)向SharedPreferences.Editor对象中添加数据,如添加一个布尔型数据使用putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。
(3)调用apply()方法将添加的数据提交,从而完成数据存储操作。
下面创建一个SharedPreferencesTest的例子来说明SharedPreferences的存储方式(第一、第二个方法):
首先创建包含一个Button控件的布局activity_main,用于触发存储数据的操作:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/savedata"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save data"/>
</LinearLayout>
然后在MainActivity中将数据存储到SharedPreferences文件中:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button saveData = (Button) findViewById(R.id.savedata);
Button readData = (Button) findViewById(R.id.readdata);
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v){
//1.Context类中的getSharedPreferences()方法
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
//2.Activity类中的getPreferences()方法
//SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
editor.putString("name", "Roy");
editor.putInt("age", 20);
editor.putBoolean("Male", true);
editor.apply();
}
});
}
}
在oncreate()中注册的点击事件里面,通过getSharedPreferences()方法指定用于存储数据的SharedPreferences文件的名字为data(方法二通过getPreferences()方法指定操作模式,SharedPreferences文件名默认为活动类名MainActivity),并得到SharedPreferences.Editor对象。然后通过put方法向该对象添加不同类型的数据,最后调用apply()方法进行提交,完成数据存储。
2.2 从SharedPreferences中读取数据
SharedPreferences对象中提供了一系列的get方法,用于对存储数据的读取,每种get方法对应了SharedPreferences.Editor中的put方法,比如读取布尔型数据就使用getBoolean()方法,读取字符串数据就使用getString()方法。get方法都接收两个参数,第一个参数是键,传入存储数据时使用的键就可以得到相应的值;第二个参数是默认值,当传入的键找不到相应的值的时候就会返回默认值。
下面基于上面的示例代码继续进行开发:
首先在activity_main.xml中添加一个用于触发读取操作的Button:
<Button
android:id="@+id/readdata"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Read data"/>
然后在MainActivity的onCreate()方法中注册该按钮的点击事件:
Button readData = (Button) findViewById(R.id.readdata);
readData.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//1.Context类中的getSharedPreferences()方法
SharedPreferences gsp = getSharedPreferences("data", MODE_PRIVATE);
//2.Activity类中的getPreferences()方法
//SharedPreferences gsp = getPreferences(MODE_PRIVATE);
String name = gsp.getString("name", "");
int age = gsp.getInt("age", 0);
Boolean isMan = gsp.getBoolean("Male", true);
String toast = "name is " + name + "\nage is " + age +"\nMale? " + isMan;
Toast.makeText(MainActivity.this, toast, Toast.LENGTH_LONG).show();
}
});
通过getSharedPreferences()方法获取SharedPreferences对象,再通过get方法获取到数据后,通过toast显示出来。
2.3 记住密码小例子
(上文中第三个方法:PreferenceManager类中getDefaultSharedPreferences()的用法)
首先创建一个布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="18sp"
android:text="Account:"/>
<EditText
android:id="@+id/account"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="18sp"
android:text="Password:"/>
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:inputType="textPassword"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/remember_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="Remember password" />
</LinearLayout>
<Button
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="Login"/>
</LinearLayout>
效果如下图所示:
然后在LoginActivity中通过PreferenceManager类中的getDefaultSharedPreferences()方法实现账户密码的存储读取操作:
public class LoginActivity extends AppCompatActivity {
private EditText accountEdit;
private EditText passwordEdit;
private CheckBox rememberPassword;
private Button login;
private SharedPreferences sp;
private SharedPreferences.Editor spEditor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
accountEdit = (EditText) findViewById(R.id.account);
passwordEdit = (EditText) findViewById(R.id.password);
rememberPassword = (CheckBox) findViewById(R.id.remember_password);
login = (Button) findViewById(R.id.login);
sp = PreferenceManager.getDefaultSharedPreferences(this);
boolean isRemember = sp.getBoolean("isRemember", false);
if(isRemember) { //若上次选中了记住密码,则将账户密码信息输出到文本框中
String account = sp.getString("account", "");
String password = sp.getString("password", "");
accountEdit.setText(account);
passwordEdit.setText(password);
rememberPassword.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("123456") && password.equals("654321")){//验证账户密码
spEditor = sp.edit();
if(rememberPassword.isChecked()) { //若记住密码选项已选中
spEditor.putString("account", account);
spEditor.putString("password", password);
spEditor.putBoolean("isRemember", true);
} else {
spEditor.clear();
}
spEditor.apply();
Toast.makeText(LoginActivity.this,"Login success!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LoginActivity.this, "account and password is invalid", Toast.LENGTH_SHORT).show();
}
}
});
}
}
首先通过PreferenceManager.getDefaultSharedPreferences()方法(传入当前Context)获取到SharedPreferences对象,在点击登录后检测记住密码的复选框,若选中则通过SharedPreferences.Editor对象的putString()、putBoolean()方法进行数据存储,最终提交数据。然后在每次运行onCreate()的时候,通过SharedPreferences对象的getBoolean()方法查看上次登陆时是否选中记住密码,若选中则读取SharedPreferences文件的数据并还原到文本框中。
需要注意的是,将密码以明文形式存储在SharedPreferences文件中是很不安全的,很容易会被盗取,因此在正式的项目中,SharedPreferences还需要结合加密算法对密码进行保护才行。
精简记忆版:
//步骤一、获取SharedPreferences对象的Editor对象
//1.通过Context类中的getSharedPreferences()方法获取SharedPreferences对象然后调用Editor获取editor对象
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
//2.通过Activity类中的getPreferences()方法获取SharedPreferences对象
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
//3.通过PreferenceManager类中的getDefaultSharedPreferences()方法获取对象
SharedPreferences.Editor spEditor = PreferenceManager.getDefaultSharedPreferences(this).edit();
//步骤二、通过Editor对象进行存储数据
//通过Editor对象调用put方法进行键值对的数据存储,最后通过apply方法保存数据
spEditor.putString("account", account);
spEditor.apply();
//步骤三、读取:先试用上文三种方法获取SharedPreferences对象,然后通过get方法来取数据
String name = gsp.getString("name", "");