概述
持久化技术就是将内存中的瞬时数据保存到存储设备中,保证在手机关机或某一应用程序关闭的时候,数据不会丢失。
Android存储文件和数据的地方:
- RAM、ROM、内存(内部存储器)、
- APP程序里面(Assets,raw,res),
- SD卡(早期的安卓的可以插卡,现在的不支持了,但是有些 arm板 嵌入式方向的还是带卡槽的)
- 网络
(参考dadachenchen的文章,原文:https://blog.youkuaiyun.com/dadachenchen/article/details/84347616)
- RAM、ROM 这些东西我们就别碰了,不然一大堆问题,Environment.getRootDirectory() 需要获取root权限,不合适
- 内存和SD卡 大家得理解 Environment.getExternalStorageState() 代表的是什么意思,不是插卡的SD卡,而是说你买了开发板、手机,厂家送你的存储地方(直接你得让他送你哈)。 这部分作为主要的存储路径,小数据和大数据都适用。
- SD卡,黑色那张卡,老古董,现在手机都没有了,不建议大家使用
- 网络,请求自己的服务器,读取数据,URI的方式,httpClient post 和 get 两种请求数据的方式
Android中主要提供了3中数据持久化方式:
- 文件存储
- AharePrefernces存储
- SQLite数据库存储
- 保存于手机SD卡(不推荐)
在AS中查看模拟器文件存储的方式:
可以在侧边栏打开Device File Explorer选择相应的文件夹进入查看(一般为data/data/package name/files)
一:文件存储
Android中最基本的数据存储方式,它不对存储的任何东西进行任何格式化的处理,所有数据元丰不动的保存到文件中。因此适用于存储一些简单的文本数据或二进制数据。
利用Context中openFileOutput()方法,可以将数据存储到指定的文件中。
利用Context中openFileInput()方法,可以从指定文件中读取数据。
(所有文件默认存储到/data/data/<package name>/files目录下)
/*
* 利用java IO流的形式完成对文件的存储(原样存储)
* */
/*
*@author: banzh
*@function: 从存储文件中恢复数据到TextView中,测试数据的保存
* 默认从data/data/package name/files目录下恢复文件。
* 所以openFileInput()方法只是默认提供files目录下的DATA文件即可
*@time 2019/5/24 18:15
**/
private String load() {
FileInputStream fileInputStream;
BufferedReader reader = null;
StringBuilder builder = new StringBuilder();
try {
fileInputStream = getActivity().openFileInput("DATA");
reader = new BufferedReader(new InputStreamReader(fileInputStream));
String line = "";
while ((line = reader.readLine()) != null){
builder.append(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return String.valueOf(builder);
}
/*
*@author: banzh
*@function: 利用java IO 流的形式保存数据(原样保存)
* 数据默认保存到data/data/package name/files/DATA中
*@time 2019/5/24 18:16
**/
private void save(String input) {
FileOutputStream outputStream = null;
BufferedWriter bufferedWriter = null;
try {
outputStream = getActivity().openFileOutput("DATA", Context.MODE_PRIVATE);
bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write(input);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bufferedWriter != null){
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
二:SharedPreferences存储
SharedPreferences是利用键值对的形式来存储数据的,且支持不同的数据类型,在对数据操作(读取)的时候通过对应的键将其内容读取出来。
SharedPreferences的文件都是存放在/data/data/<package name>/shared——prefs/目录下。
获取SharedPreferences对象的方式:
- Context类中的getSharedPreferences()
- Activity类中的getPreferences()
- PreferenceManager类中的getDefaultSharedPreferences()
/*
*@author: banzh
*@function:在button的点击事件中存储EditText所输入的数据
*@time 2019/5/24 18:39
**/
button_save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*
* 调用第三种方式实现SharedPreferences
* */
/*1.
*调用SharedPreferences对象的edit方法获取一个SharedPreferences.Editor对象
* */
SharedPreferences.Editor editor = getActivity().getSharedPreferences("share_data", Context.MODE_PRIVATE).edit();
/*2.
* 向SharedPreferences.Editor对象中添加数据
* */
String input = editText.getText().toString();
editor.putString("msg", input);
/*3.
* 用apply()方法,将数据提交
* */
editor.apply();
}
});
/*
*@author: banzh
*@function:在button的点击事件中恢复数据
*@time 2019/5/24 18:39
**/
button_retext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*
* 调用第一种方法实现SharedPreferences
* */
SharedPreferences preferences = getContext().getSharedPreferences("share_data", Context.MODE_PRIVATE);
String msg = preferences.getString("msg", "无存储内容!");
textView.setText(msg);
}
});
(从图中可以看出SharedPreferences是利用XML形式存储文件的)
三:SQLite数据库存储
SQLite是一款轻量级的关系型数据库,运行速度快,占用资源少。它不仅支持标准的SQL语法,而且遵循数据库的ACID事务。当需要存储大量复杂的关系型数据的时候,SQLite比前两种都更适合。
Android中提供了一个SQLiteOpenHelper帮助类,帮助管理数据库。它是一个抽象类,必须要自己实现类去继承它。
SQLiteOpenHelper的两个重要方法:
- onCreate();
- onUpgrade();
其他重要的实例方法:
- getReadableDatabase();
- getWritableDatabase();
这两个方法可以创建或打开一个现有的数据库,并返回一个可对数据库进行读写操作的对象。当数据库不可写入时,getReadableDatabase()返回的对象只能以读的方式去打开数据库。而getWritableDatabase();会报异常。
数据库文件会存放在data/data/package name/databases/目录下。
以下是对象实现,相关注册在代码中体现:
package com.example.myboring.bottombar.fragment;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.example.myboring.R;
import com.example.myboring.database.MyDatabaseHelper;
import static android.content.ContentValues.TAG;
public class Fragment3 extends Fragment {
View view;
Button btn_editText;
TextView textView;
android.widget.ScrollView scrollView;
Button button_save;
Button button_update;
Button button_delect;
Button button_query;
EditText edit_book_name;
EditText edit_book_author;
EditText edit_book_pages;
EditText edit_book_price;
String name;
String author;
String pages;
String price;
private MyDatabaseHelper dbHleper;
private SQLiteDatabase db;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment3, container, false);
initView();
return view;
}
private void initView() {
btn_editText = view.findViewById(R.id.btn_editText);
textView = view.findViewById(R.id.textView);
scrollView = view.findViewById(R.id.scrollView);
button_save = view.findViewById(R.id.button_save);
button_update = view.findViewById(R.id.button_update);
button_delect = view.findViewById(R.id.button_delect);
button_query = view.findViewById(R.id.button_query);
//实例化MyDatabaseHelper的对象
//可根据对数据库的改变然后将版本升级即可
dbHleper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
/*
* 向数据库中静态保存数据的相应实现
* */
button_save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//完成BookStore.db数据库的创建,初始化版本号为一
db = dbHleper.getWritableDatabase();
/*
* 用insert语句,向数据库中添加数据
* 向ContentValues中添加每列相对应的数据,
*
* "create table Book ("
*+ "id integer primary key autoincrement,"
*+ "author text,"
*+ "price real,"
*+ "pages integer,"
*+ "name text)";
* */
/*
* 若中文存储会出现乱码问题:
* String s = "三国演义";
* String utf8Str = new String(s.getBytes("utf-8"), "utf-8);
* */
ContentValues values = new ContentValues();
values.put("name", "西游记");
values.put("author", "第一个人");
values.put("price", 100);
values.put("pages", 9999);
//完成数据的添加之后,用insert语句完成数据库的添加
db.insert("Book", null, values);
//清楚values的值,然后开始添加第二条数据
values.clear();
values.put("name", "三国演义");
values.put("author", "第二个人");
values.put("price", 1000);
values.put("pages", 10000);
db.insert("Book", null, values);
Log.d(TAG, "button_save-->onClick:<<<<<<< " + "数据添加完成!!!");
}
});
/*
* 更新数据库的代码实现
* */
button_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
db = dbHleper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 0.1111);
db.update("Book", values, "name = ?",
new String[]{
"西游记"
});
}
});
button_delect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
db = dbHleper.getWritableDatabase();
db.delete("Book", "pages > ?",
new String[]{
"100"
});
textView.setText("");
}
});
/*
* 查询数据库的代码实现
* */
button_query.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
db = dbHleper.getWritableDatabase();
//查询表中现存的所有数据
Cursor cursor = (Cursor) db.query("Book", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
//遍历cursor对象,取出数据并输出
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int price = cursor.getInt(cursor.getColumnIndex("price"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
String data = "+++++++++++++++++++++++++++++ \n" +
"书名:" + name + "\n" +
"作者: " + author + "\n" +
"书页: " + pages + "\n" +
"价格: " + price + "\n"
+ "+++++++++++++++++++++++++++++ \n\n";
textView.append(data);
} while (cursor.moveToNext());
}
cursor.close();
}
});
/*
* 利用对话框功能动态的添加书籍信息,原理同静态保存数据的方法
* 此代码中对话框的功能实现值得仔细研究
* */
btn_editText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
LayoutInflater inflater = LayoutInflater.from(getContext());
View ADview = inflater.inflate(R.layout.editbook, null);
builder.setTitle("请输入书籍信息:");
builder.setMessage("在这里你可以添加相信的图书资源到数据库中!");
builder.setView(ADview);
builder.setPositiveButton("添加", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db = dbHleper.getWritableDatabase();
ContentValues values = new ContentValues();
name = edit_book_name.getText().toString().trim();
author = edit_book_author.getText().toString().trim();
pages = edit_book_pages.getText().toString().trim();
price = edit_book_price.getText().toString().trim();
values.put("name", name);
values.put("author", author);
values.put("price", new Integer(pages));
values.put("pages", new Integer(price));
db.insert("Book", null, values);
dialog.dismiss();
}
});
/*
* 调用setView方法只会标题和按钮之间的内容:
* ((AlertDialog) dialog).setView(ADview);
*
* 而调用setContentView方法则会覆盖整体的View:
* dialog.setContentView();
* */
AlertDialog dialog = builder.create();
dialog.show();
edit_book_name = dialog.findViewById(R.id.edit_book_name);
edit_book_author = dialog.findViewById(R.id.edit_book_author);
edit_book_pages = dialog.findViewById(R.id.edit_book_pages);
edit_book_price = dialog.findViewById(R.id.edit_book_price);
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
new AlertDialog.Builder(getContext())
.setTitle("添加书籍信息")
.setMessage("一本书的销售信息")
.setView(R.layout.editbook)
.setPositiveButton("添加", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db = dbHleper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("author", author);
values.put("price", new Integer(pages));
values.put("pages", new Integer(price));
db.insert("Book", null, values);
Log.d(TAG, "button_save-->onClick:<<<<<<< " + "数据添加完成!!!");
}
}).show();
name = edit_book_name.getText().toString().trim();
author = edit_book_author.getText().toString().trim();
pages = edit_book_pages.getText().toString().trim();
price = edit_book_price.getText().toString().trim();
}*/
}
});
}
/*
* 废掉的代码
* */
private void addBook() {
db = dbHleper.getWritableDatabase();
ContentValues values = new ContentValues();
String name = edit_book_name.getText().toString().trim();
String author = edit_book_author.getText().toString().trim();
String pages = edit_book_pages.getText().toString().trim();
String price = edit_book_price.getText().toString().trim();
values.put("name", name);
values.put("author", author);
values.put("price", new Integer(pages));
values.put("pages", new Integer(price));
db.insert("Book", null, values);
Log.d(TAG, "button_save-->onClick:<<<<<<< " + "数据添加完成!!!");
}
/*
* 废掉的代码
* */
}
四:LitePal的使用
开源库LitePal是一款Android数据库框架,实现了对数据库操作的有一层封装。配置LitePal的方法不在累赘。
具体的信息请参照https://github.com/LitePalFramework/LitePal(LitePal主页)
代码如下:
package com.example.myboring.bottombar.fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.example.myboring.R;
import com.example.myboring.database.Person;
import org.litepal.LitePal;
import org.litepal.crud.LitePalSupport;
import java.util.List;
public class Fragment4 extends Fragment {
View view;
EditText editText;
TextView textView;
Button create_db;
Button save_db, update_db, delete_db, query_db;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment4, container, false);
initView();
return view;
}
private void initView() {
create_db = view.findViewById(R.id.create_db);
save_db = view.findViewById(R.id.save_db);
update_db = view.findViewById(R.id.update_db);
delete_db = view.findViewById(R.id.delete_db);
query_db = view.findViewById(R.id.query_db);
textView = view.findViewById(R.id.textView);
initOther();
}
private void initOther() {
create_db.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LitePal.getDatabase();
}
});
save_db.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*private double height;
private String name;
private String sex;
private String address;*/
Person person = new Person();
person.setHeight(180.00);
person.setName("bai");
person.setSex("男");
person.setAddress("中国西安");
person.save();
}
});
update_db.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Person person_1 = new Person();
person_1.setAddress("中国美国");
person_1.setName("zai");
person_1.setHeight(111);
person_1.setSex("女");
person_1.save();
person_1.setHeight(200);
person_1.updateAll("name = ? ", "zai");
/*
不推荐使用这种方法更新数据
person_1.setHeight(167);
person_1.save();*/
}
});
delete_db.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LitePal.deleteAll(Person.class, "height < ?", "220");
textView.setText("");
}
});
query_db.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Person> list_person = LitePal.findAll(Person.class);
for (Person person : list_person) {
String msg = "++++++++++++++++++\n"
+ "姓名: " + person.getName() + "\n"
+ "性别: " + person.getSex() + "\n"
+ "身高: " + person.getHeight() + "\n"
+ "地址: " + person.getAddress() + "\n"
+ "++++++++++++++++++\n\n";
textView.append(msg);
}
}
});
}
}