目录
一、持久化技术简介
持久化技术提供了一种机制可以让数据从内存转换到存储设备中
Android提供了3种方式实现数据持久化功能:文件存储、SharedPreference存储和数据库存储
二、文件存储
1.将数据存储到文件中
Context类提供了一个openFileOutput()方法,可以将数据存储到指定的文件。
第一个参数是文件名(不包含路径),第二个参数是文件的操作模式,MODE_PRIVATE是默认操作模式,表示指定同样文件名时,写入的内容会覆盖原有的内容;MODE_APPEND表示文件名已存在时追加内容,不存在时创建新文件。
public class MainActivity extends AppCompatActivity {
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = findViewById(R.id.edit);
}
@Override
protected void onDestroy() {
super.onDestroy();
String s = edit.getText().toString();
save(s);
}
public void save(String s) {
FileOutputStream out = null;
BufferedWriter writer = null;
try {
//openFileOutput是ContextWrapper类的方法
out = openFileOutput("data", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.从文件中读取数据
public class MainActivity extends AppCompatActivity {
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = findViewById(R.id.edit);
String s = load();
//TextUtils.isEmpty()方法可以一次性进行两种空值的判断,传入的字符串等于null或等于空字符串时都会返回true
if(!TextUtils.isEmpty(s)){
edit.setText(s);
//调用setSelection()方法将输入光标移动到文本的末尾位置以便继续输入
edit.setSelection(s.length());
Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show();
}
}
...
private String load(){
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder builder = new StringBuilder();
try {
in = openFileInput("data");
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine())!=null){
builder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return builder.toString();
}
}
三、SharedPreference存储
以键值对的方式存储数据
获取Sharedpreferences对象的三种方法:
- Context类中的getSharedPreferences()方法:第一个参数指定SharedPreferences文件的名称,指定的文件不存在则会创建一个,第二个参数指定操作模式,只有MODE_PRIVATE一种模式可选,表示只有当前的应用程序才可以对这个SharedPreferences文件进行读写
- Activity类中的getPreferences()方法:只接收一个操作模式参数,因为这个方法会自动将当前活动的类名作为SharedPreferences的文件名
- PreferenceManager类中的getDefaultSharedPreferences()方法:这是一个静态方法,接收一个Context参数,自动使用当前应用程序的包名作为前缀来命名Sharedpreferences文件
1.将数据存储到SharedPreferences中
- 调用SharedPreferences对象的edit()方法获取SharedPreferences.Editor对象
- 使用putString()或putBoolean()方法向SharedPreferences.Editor对象添加数据
- 调用apply()方法将添加的数据提交
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button save = findViewById(R.id.save);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SharedPreferences.Editor editor = getSharedPreferences("data", Context.MODE_PRIVATE).edit();
editor.putString("name", "jack");
editor.putInt("age", 28);
editor.putBoolean("married", false);
//提交,完成数据存储操作
editor.apply();
}
});
}
}
2.从SharedPreferences中读取数据
调用SharedPreferences对象的getString(),getInt()和getBoolean()方法,这些get方法接收两个参数,第一个参数是键,第二个参数是默认值
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Jack";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
Button restore = findViewById(R.id.restore);
restore.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SharedPreferences pref = getSharedPreferences("data", Context.MODE_PRIVATE);
String name = pref.getString("name", "");
int age = pref.getInt("age", 0);
boolean married = pref.getBoolean("married", false);
Log.d(TAG, "name is " + name);
Log.d(TAG, "name is " + age);
Log.d(TAG, "name is " + married);
}
});
}
}
3.实现记住密码的功能
public class LoginActivity extends BaseAcitvity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_layout);
Button login = findViewById(R.id.login);
EditText account = findViewById(R.id.account);
EditText password = findViewById(R.id.password);
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
CheckBox rememberPassword = findViewById(R.id.remember_password);
boolean aBoolean = pref.getBoolean("remember_password", false);
if(aBoolean){
String account1 = pref.getString("account", "");
String password1 = pref.getString("password", "");
account.setText(account1);
password.setText(password1);
rememberPassword.setChecked(true);
}
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String s_acount = account.getText().toString();
String s_password = password.getText().toString();
if ("admin".equals(s_acount) && "123456".equals(s_password)) {
SharedPreferences.Editor editor = pref.edit();
if(rememberPassword.isChecked()){
editor.putString("account",s_acount);
editor.putString("password",s_password);
editor.putBoolean("remember_password",true);
}else {
editor.clear();
}
editor.apply();
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
}else {
Toast.makeText(LoginActivity.this, "account or password is invalid", Toast.LENGTH_SHORT).show();
}
}
});
}
}
四、SQLite数据库存储
1.创建数据库
SQLiteOpenHelper抽象类
两个抽象方法:onCreate()和onUpgrade()分别实现创建数据库和升级数据库的逻辑
两个实例方法:getReadableDatabase()和getWritableDatabase(),两个方法都可以创建或打开一个现有的数据库,并返回一个可对数据库进行读写操作的对象SQLiteDatabase
两个构造方法,一般使用参数少一点的构造方法:第一个参数是Context,第二个参数是数据库名,第三个参数一般是null,第四个参数表示当前数据库的版本号
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book (" +
"id integer primary key autoincrement," +
"author text," +
"price real," +
"pages integer," +
"name text" +
")";
private Context mcontext;
public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mcontext=context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(mcontext, "创建Book表成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
Button createDatabase = findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
}
//sqlite3加上数据库名的路径就可以打开数据库
C:\Users\51074>sqlite3 "D:\it\zklianxi\BookStore.db"
SQLite version 3.32.2 2020-06-04 12:58:43
Enter ".help" for usage hints.
//查看数据库目前有哪些表
sqlite> .table
Book android_metadata
//查看建表语句
sqlite> .schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE Book (id integer primary key autoincrement,author text,price real,pages integer,name text);
CREATE TABLE sqlite_sequence(name,seq);
//.exit或.quit命令可以退出数据库的编辑
sqlite> .exit
2.升级数据库
在onUpgrade()方法中先将存在的表drop掉,再在里面调用onCreate()方法
构造方法的第四个参数传一个比之前大的数,就可以让onUpgrade()方法运行
3.添加数据
调用SQLiteDatabase实例的insert()方法可以添加数据,第一个参数是表名,第二个参数传入null,第三个参数是一个ContentValues对象,它提供了一系列的put()方法重载
Button addData = findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase database = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name","harry");
values.put("author","jack");
values.put("pages",19);
values.put("price",19.99);
database.insert("Book",null,values);
values.clear();
values.put("name","potter");
values.put("author","jack");
values.put("pages",20);
values.put("price",20.00);
database.insert("Book",null,values);
}
});
4.更新数据
update()方法对所有数据进行更新,第一个参数是表名,第二个参数是ContentValues对象,第三四个参数用于约束更新某一行或某几行的数据,不指定默认更新所有行
Button updateData = findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price",2000);
db.update("Book",values,"name = ?",new String[]{"potter"});
}
});
5.删除数据
delete()方法对数据进行删除,第一个参数是表名,第二三个参数用于约束删除某一行或某几行的数据,不指定默认删除所有行
Button deleteData = findViewById(R.id.delete_data);
deleteData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
Log.d("123123","11111");
db.delete("Book","pages < ?",new String[]{"70"});
}
});
6.查询数据
query()方法对数据进行查询,第一个参数是表名,第二个参数用于指定去查哪几列,第三四个参数用于约束查询某一行或某几行的数据,第五个参数用于指定需要group by的列,第六个参数对group by进行过滤,第七个参数指定查询结果的排序方式
query()方法返回一个Cursor对象
Button queryData = findViewById(R.id.query_data);
queryData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if(cursor.moveToFirst()){
do{
String author = cursor.getString(cursor.getColumnIndex("author"));
Double price = cursor.getDouble(cursor.getColumnIndex("price"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
String name = cursor.getString(cursor.getColumnIndex("name"));
Log.d("Mainactivity","author is : "+author);
Log.d("Mainactivity","price is : "+price);
Log.d("Mainactivity","pages is : "+pages);
Log.d("Mainactivity","name is : "+name);
}while (cursor.moveToNext());
}
}
});
7.使用SQL操作数据库
除了查询数据的时候调用的是SQLiteDatabase的rawQuery()方法,其他操作都是调用execSQL()方法
Button queryData = findViewById(R.id.query_data);
queryData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
// Cursor cursor = db.query("Book", null, null, null, null, null, null);
Cursor cursor = db.rawQuery("select * from Book", null);
if(cursor.moveToFirst()){
do{
String author = cursor.getString(cursor.getColumnIndex("author"));
Double price = cursor.getDouble(cursor.getColumnIndex("price"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
String name = cursor.getString(cursor.getColumnIndex("name"));
Log.d("Mainactivity","author is : "+author);
Log.d("Mainactivity","price is : "+price);
Log.d("Mainactivity","pages is : "+pages);
Log.d("Mainactivity","name is : "+name);
}while (cursor.moveToNext());
}
}
});
五、使用LitePal操作数据库
LitePal是一款开源的Android数据库框架,采用了对象关系映射(ORM)的模式
1.配置LitePal
-
编辑app/build.gradle文件,在dependencies闭包中添加
implementation 'org.litepal.android:core:2.0.0'
-
右击app/src/main,创建assets目录,在目录下新建litepal.xml文件,编辑内容如下
<?xml version="1.0" encoding="utf-8" ?>
<litepal>
<dbname value="BookStroe"></dbname>
<version value="1"></version>
<list>
</list>
</litepal>
-
修改AndroidManifest.xml中的代码
<application
android:name="org.litepal.LitePalApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LitePalTest">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
2.创建和升级数据库
创建数据库:
-
创建一个Java bean,比如Book类
-
将Book类添加到映射模型列表中,修改litepal.xml中的代码
-
调用Connector.getDatabase()方法就是一次最简单的数据库操作
<?xml version="1.0" encoding="utf-8" ?>
<litepal>
<dbname value="BookStore"></dbname>
<version value="1"></version>
<list>
<mapping class="com.jack.litepaltest.Book"></mapping>
</list>
</litepal>
升级数据库:
-
修改Book类,再创建一个Category类
-
将Category类也添加到映射模型列表中,并且将版本号加1
3.使用LitePal添加数据
-
Java bean类继承DataSupport类
-
创建Java bean的实例,调用set方法,最后调用save()方法完成数据库添加操作
4.使用LitePal更新数据
第一种更新方式:
对已存储对象重新设值,已存储对象是根据调用model.isSaved()方法的结果来判断
第二种更新方式:
Book book = new Book();
book.setPrice(3000.0);
book.setPress("potter");
book.updateAll("name = ? and author = ? ","harry","jack");
5.使用LitePal删除数据
和更新数据一样也有两种,第二种是:
DataSupport.deleteAll(Book.class,"name = ?","potter");
6.使用LitePal查询数据
List<Book> books = DataSupport.findAll(Book.class);
LitePal还有很多查询API,详见书内,就不记笔记了
完!