持久化(Persistence)
由于这个东西和mybatis比较像,而且没有太多的内容,写的比较简单。
简介
Android系统中主要听过了三种方式用于简单地实现数据持久化功能:文件存储、sharedpreference存储以及数据库存储。
这一章默认是在模拟器上学习了,华为手机如果没有root的话,是无法进入根目录(/
)文件夹下的,也就没办法去/data/app/com.ssozh.filepersistentcetest
下查看相关文件了。而华为的内部存储所在的文件夹是/storage/emulated/0/
。
文件存储
文件存储是Android中最基本的数据存储方法,它不对存储的内容进行任何格式化处理,所有数据都是原封不动的保存到文件中。
存储
Context类提供了一个openFileOutput()方法,可以用于将数据存储到指定的文件中。
FileOutputStream openFileOutput(fileName, OPFlag)
输入参数:
fileName是不包括路径的,所有文件都是默认存储到/data/data/<package name>/files/目录下
OPFlag:文件的操作模式,主要有MODE_PRIVATE(默认)和MODE_ADDEND两种模式,前者是覆盖,后者是追加。另外还有MODE_WORLD_
输出参数:
FileOutputStream对象,得到这个对象之后就可以使用java流的方式将数据写入文件中了。
假设我们希望关闭app的时候,存储相关数据:
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.edit = (EditText)findViewById(R.id.edit);
String inputText = load();
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 = this.edit.getText().toString();
save(inputText);
}
private void save(String inputText) {
FileOutputStream out = null;
BufferedWriter writer = null;
try {
out = openFileOutput("data", Context.MODE_APPEND);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(inputText);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
读取
类似于将数据存储到文件中,Context类中还提供了一个openFileInput()方法,用于文件中读取数据。
FileInputStream openFileInput(fileName)
输入参数:
fileName是不包括路径的,所有文件都是默认存储到/data/data/<package name>/files/目录下.
输出参数:
FileInputStream对象,得到这个对象之后就可以使用java流的方式将数据读取文件中了。
我们希望再次启动的时候,载入相关数据(注意这个循环会造成文件越存储越大):
private String load(){
FileInputStream inputStream = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
inputStream = openFileInput("data");
reader = new BufferedReader(new InputStreamReader(inputStream));
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存储
不同于文件的存储方式,sharedpreference是使用键值对的方式来来存储数据的。而且sharedpreferences还支持多种不同的数据存储类型。可以是整型、字符串等等。
存储
- 想要使用sharedpreferences存储数据,首先需要获取对象
SharedPreferences
。主要有两种方法:- Context类中的
getSharedPreferences()
方法:- 这个方法和上面的文件存储方法
openFileOutput
基本一样,包括文件名和写入模式的选择两个参数。 - 区别在于默认存放在
/data/data/<package name>/shared_prefs
目录下。
- 这个方法和上面的文件存储方法
- Activity类中的
getPreferences()
方法:- 这个方法只接受操作模式这一个参数。因为是用这个方法时会自动将当前activity的类名作为sharedPreferences的文件名。
- Context类中的
- 调用
SharedPreferences
对象的edit()方法获取一个SharedPreferences.Editor
对象。 - 向
SharedPreferences.Editor
对象中添加数据,比如添加boolran型,就使用putBoolean方法。 - 调用
apply()
方法将添加的数据提交、从而完成数据存储操作。
读取
还是获取SharedPreferences
对象,然后调用get方法即可。
get方法接受两个参数,第一个是key,第二个参数是默认值,即表示当传入的键找不到对应的值时的返回值。
记住密码
在上一节的登陆部分,添加一个checkBox控件,增加记住密码功能。
public class LoginActivity extends BaseActivity {
private EditText accountEdit;
private EditText passwordEdit;
private Button login;
private CheckBox rememberPassword;
private SharedPreferences pref;
private SharedPreferences.Editor editor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
login = (Button)findViewById(R.id.login);
rememberPassword =(CheckBox) findViewById(R.id.remember_password);
pref = PreferenceManager.getDefaultSharedPreferences(this);
editor = pref.edit();
accountEdit = (EditText) findViewById(R.id.account_edit);
passwordEdit = (EditText) findViewById(R.id.password_edit);
// 读取SharedPreferences
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);
rememberPassword.setChecked(true);
}
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if("admin".equals(accountEdit.getText().toString()) && "123456".equals(passwordEdit.getText().toString())){
if(rememberPassword.isChecked()){
// 存储SharedPreferences
editor.putBoolean("remember_password",true);
editor.putString("account",accountEdit.getText().toString());
editor.putString("password",passwordEdit.getText().toString());
}else {
// 否则清除数据
editor.clear();
}
editor.apply();
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
}else {
// TODO:华为键盘会挡住这个toast
Toast.makeText(LoginActivity.this,"account or password is invalid",Toast.LENGTH_SHORT).show();
}
}
});
}
}
SQLite数据库存储
基本操作
创建、更新数据库
要想在通过SQLite对数据库进行操作,首先需要创建一个子类继承SQLiteOpenHelper,然后重写他的方法:
- onCreate:创建数据库
- onUpgrade:升级数据库
- 升级数据库的方法:在
onUpgrade
方法中先把之前的数据库删除,然后重新创建,同时注意在new databaseHelper
的时候修改版本号 - 注意:如果不修改版本号,是不会执行onUpgrade操作的!!!
- 升级数据库的方法:在
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 后面的1 -> 2表示数据库升级了,比如添加了一个table 之类的行为都叫update
dbHelper = new MydatabaseHelper(this,"BookStore.db",null,2);
Button createDb = (Button) findViewById(R.id.create_database);
createDb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext, "create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists category");
onCreate(db);
}
【adb在F:\Android\SDK\platform-tools
目录下,可以先添加path】
可以考虑通过adb shell进行adb调试,但是由于华为不能root,好像无法访问/data/data下面的app:
这里可以查看最下方的Android studio自带的database inspection:
添加数据CRUD
通过调用SQLiteOpenHelper的getReadableDatabase
或getWriteableDatabase
方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个SQLiteDatabase对象,借助这个对象就可以进行CRUD操作了。
操作方式基本一致:
-
通过dbHelper.getWriteableDatabase(),找到数据库db
-
db.insert() , db.query()等方法进行CRUD
-
其中CU的对象是ContentValues
-
query和delete不太一样
@Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); // 开始组装第一条数据 values.put("name", "The Dan Vinci Code"); values.put("author","Dan Brown"); values.put("pages", 154); values.put("price",16.69); db.insert("Book",null,values); values.clear(); // 开始组装第二条数据 values.put("name", "The Lost Symbol"); values.put("author","Dan Brown"); values.put("pages", 510); values.put("price",19.95); db.insert("Book",null,values); }
-
修改:
-
删除:
db.delete("Book", "pages > ?" , new String[] {"500"});
-
查询:
@Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); // 查询db表中的所有数据 Cursor cursor = db.query("Book", null, null, null, null, null, null); if(cursor!=null) { while (cursor.moveToNext()){ String[] columns = new String[]{"name", "author", "pages", "price"}; for(String column : columns){ printOnLog(cursor,column); } } } } private void printOnLog(Cursor cursor, String column){ // String name = cursor.getString(cursor.getColumnIndex("name")); Object tmp = cursor.getString(cursor.getColumnIndex(column)); Log.d(TAG,"book " + column + " is " + tmp.toString()); }
直接使用SQL语句操作数据库(有点像mybatis):
db.execSQL("insert into Book(name, author, pages, price) values(?, ?, ?, ?)", new String[]{"","","",""});