第六章 数据存储权方案——详解持久化技术
6.1 持久化技术简介
- 概述:Android 系统中主要提供了3种方式用于简单地实现数据持久化功能,即文件存储、SharedPreference存储以及数据库存储。当然,除了这3种方式之外,你还可以将数据保存在手机的SD卡中,不过使用文件、SharedPreference 或数据库来保存数据会相对更简单一些,
而且比起将数据保存在SD卡中会更加地安全。
6.2 文件存储
6.2.1 将文件存储到文件中
-
Context类中提供了一个openFileOutput()方法,这个方法接收两个参数,第一个参数是文件名,在文件创建的时候使用的就是这个名称,注意这
里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data//files/目录下的。第二个参数是文件的操作模式,主要有两种模式可选,MODE_ PRIVATE
和MODE APPEND。其中MODE_ PRIVATE 是默认的操作模式,表示当指定同样文件名的时候,
所写入的内容将会覆盖原文件中的内容,而MODE_ APPEND 则表示如果该文件已存在,就往文
件里面追加内容,不存在就创建新文件。 -
给主活动界面添加EditText控件用于录入数据
<?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" > <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/type_something_here" android:id="@+id/edit"/> </LinearLayout>
-
修改主活动代码,使其再销毁活动时实现数据的存储:
package com.example.filepersistencetest; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.os.Bundle; import android.widget.EditText; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class MainActivity extends AppCompatActivity { 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); } public 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(); } } } }
6.2.2 从文件中读取数据
-
概述:Context 类中还提供了一个openFileInput()方法,用于从文件中读取数据。这个方法要比openFile0utput()简单一些,它只接收一个参数,即要读取的文件名,然后系统会自动到/data/data//files/目录下去加载这个文件,并返回一个
FileInputStream对象,得到了这个对象之后再通过Java流的方式就可以将数据读取出来了。 -
修改主活动代码,编写数据写入方法
package com.example.filepersistencetest; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.os.Bundle; import android.text.TextUtils; import android.widget.EditText; import android.widget.Toast; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class MainActivity extends AppCompatActivity { 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(); //输入数据 if(!TextUtils.isEmpty(inputText)) { edit.setText(inputText); edit.setSelection(1); //设置Edit的光标位置 Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show(); } } @Override protected void onDestroy() { super.onDestroy(); String inputText = edit.getText().toString(); save(inputText); } public 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(); } } } public String load() { //数据写入方法 FileInputStream in = null; BufferedReader read = null; StringBuilder content = new StringBuilder(); try { in = openFileInput("data"); //设置数据源 read = new BufferedReader(new InputStreamReader(in)); String line = ""; while ((line = read.readLine()) != null) { content.append(line); } } catch (Exception e) { e.printStackTrace(); } finally { if(read != null) { try { read.close(); } catch (IOException e) { e.printStackTrace(); } } } return content.toString(); } }
6.3 SharedPreferences存储
- 概述:不同于文件的存储方式,SharedPreferences是使用键值对的方式来存储数据的。当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过
**这个键把相应的值取出来。**而且SharedPreferences 还支持多种不同的数据类型存储,存什么数据类型就拿出什么数据类型
6.3.1 将数据存储到SharedPreferences中
-
概述:使用SharedPreference来存储数据,首先的获取到SharedPreferences对象。Android提供了3种方法用于得到SharedPreferences对象。
-
三种获得SharedPreferences对象的方式:
-
Context类中的getSharedPreferences()方法:
此方法接收两个参数,第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个SharedPreferences 文件都是存放在/data/data//shared_ _prefs/
目录下的。第二个参数用于指定操作模式,目前只有MODE _PRIVATE这一种模式可选,它是默认的操作模式,和直接传入0效果是相同的,表示只有当前的应用程序才可以对这个
SharedPreferences文件进行读写。 -
Activity类中的getPreferences()方法:
这个方法和Context中的getSharedPreferences( )方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为SharedPreferences的文件名。
-
PreferenceManager类中的getDefaultSharedPreferences()方法:
这是一个静态方法,它接收一个Context 参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences 文件。得到了SharedPreferences 对象之后,就可以开始向SharedPreferences文件中存储数据了,主要可以分为3步实现。
-
-
使用步骤:
-
调用SharedPreferences对象的edit()方法来获取一个SharedPreferences . Editor对象。
-
向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用
putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。 -
调用apply()方法将添加的数据提交,从而完成数据存储操作。
-
-
getDefaultSharedPreferences()方法,使用流程:
为活动设置一个按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/save_data"
android:text="@string/save_data"/>
</LinearLayout>
修改主活动代码,为按钮设置点击事件,点击事件为存储数据
package com.example.sharedpreferencestest;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
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.save_data);
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@SuppressLint("CommitPrefEdits")
//获取editor对象
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("name", "Tom"); //向对象中添加数据
editor.putInt("age", 28);
editor.putBoolean("married", false);
editor.apply(); //调用apply方法将添加的数据提交,完成数据的存储
}
});
}
}
- 补充:此方式类似于map集合的存储的方式,它只会为唯一键匹配唯一值,相同键会在第二添加数据时覆盖第一次添加的数据,键相同时如果类型不一样,下面出现的将对上面出现的类型进行覆盖
6.3.2 从SharedPreferences中读取数据
-
为主活动添加一个按钮并为其设置带年纪事件:
package com.example.sharedpreferencestest; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button saveData = (Button) findViewById(R.id.save_data); saveData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @SuppressLint("CommitPrefEdits") SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit(); editor.putString("name", "Tom"); editor.putInt("age", 28); editor.putBoolean("married", false); editor.apply(); Button restoreData = (Button) findViewById(R.id.restore_data); restoreData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SharedPreferences pre = getSharedPreferences("data", MODE_PRIVATE); String name = pre.getString("name", ""); int age = pre.getInt("age", 0); boolean married = pre.getBoolean("married", false); Log.d(TAG, "name is " + name); //将数据打印出来 Log.d(TAG, "age is " + age); Log.d(TAG, "married is " + married); } }); } }); } }
结果展示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zd4KwhvY-1631454087612)(C:\Users\过客\AppData\Roaming\Typora\typora-user-images\image-20210803114536805.png)]
6.3.3 实现记住密码功能
-
新控件,CheckBox:这是一个复选框控件,用户可以通过点击的方式来进行选中或取消。
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <CheckBox //添加复选框控件 android:id="@+id/remember_pass" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/remember_password" android:textSize="18sp" /> </LinearLayout>
-
再主活动设置记住密码的处理逻辑:(先判断是否点击爆粗密码的复选框,点击则通过SharedPreferences对账号密码进行存储,下次登录将其拿出,未点击则清空存储的信息)
package com.example.broadcastbestpractice; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.Toast; public class LoginActivity extends AppCompatActivity { 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.activity_login); pref = PreferenceManager.getDefaultSharedPreferences(this); accountEdit = (EditText) findViewById(R.id.account); passwordEdit = (EditText) findViewById(R.id.password); rememberPass = (CheckBox) findViewById(R.id.remember_pass); login = (Button) findViewById(R.id.login); 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 view) { String account = accountEdit.getText().toString(); String password = passwordEdit.getText().toString(); if (account.equals("admin") && pass word.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.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(); } } }); } }
6.4 SQLite 数据库
6.4.1 创建数据库
-
概述:Android为了让我们能够更加方便地管理数据库,专广]提供了一个SQLiteOpenHelper帮助类,
借助这个类就可以非常简单地对数据库进行创建和升级。 -
SQLiteOpenHelper类:此类为一个抽象类,含有两个抽象方法,onCreatae()和onUpgrade()
- 实例方法:两方法都可以创建或者打开一个现有数据库(存在则打开,否则则创建),并返回一个可对数据库进行读写操作的对象。不同:
- getReadableDatabase(): 当数据库不可写入时,将以只读的方式打开数据库
- getWritableDatabase(): 当数据库不可写入时,此方法将抛出异常
- 实例方法:两方法都可以创建或者打开一个现有数据库(存在则打开,否则则创建),并返回一个可对数据库进行读写操作的对象。不同:
-
构造方法参数说明:
- SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。
这个构造方法中接收4个参数,第一个参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的Cursor, 一般都是传入null。第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper 的实例之后,
- SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。
-
创建数据库需要创建表:需要使用建表语句
![
](C:\Users\过客\AppData\Roaming\Typora\typora-user-images\image-20210805104809457.png)
-
SQLite的数据类型很简单,只有四种:
- integer 表示整型
- real表示浮点型
- text表示文本类型
- blob表示二进制类型
-
代码实现:(先创建自己的帮助类,让其继承SQLiteOpenHelper帮助类,借助这个类就可以非常简单的对数据库进行创建和升级)
package com.example.databasetest; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.widget.Toast; 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(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context,name,factory,version); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); //将建表语句定义成为一个字符串常量,SQLiteDatabase的execSQL()方法 Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show(); //弹窗提示 } @Override public void onUpgrade(SQLiteDatabase db, int olderVersion, int newVersion) { } }
-
创建数据库:
package com.example.databasetest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { protected MyDatabaseHelper dpHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dpHelper = new MyDatabaseHelper(this,"Book.dp", null, 1); //传参 Button createDatabase = (Button) findViewById(R.id.create_database); createDatabase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dpHelper.getWritableDatabase(); //创建数据库 } }); } }
6.4…2 升级数据库
-
概述:通过onUpgrade()方法对数据库进行升级
-
修改MyDatabaseHelper中代码:
package com.example.databasetest; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.widget.Toast; 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 static final String CREATE_CATEGORY = "create table Category (" //加入category表 + "id integer primary key autoincrement, " + "category_name text, " +"category_code integer)"; private Context mContext; public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context,name,factory,version); mContext = context; } @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 olderVersion, int newVersion) { //执行更细数据库方法 db.execSQL("drop table if exists Book"); //判断是否存在此表,存在则删除 db.execSQL("drop table if exists Category"); onCreate(db); //上面不删除则此处抛异常 } }
-
当主活动中方法执行哪里的版本号大于之前的版本号,则会执行帮助类中的onUpgrade方法
6.4.3 添加数据
-
概述:其实我们可以对数据进行的操作无非有4种,即CRUD。其中C代表添加(Create), R代
表查询( Retrieve), U代表更新( Update), D代表删除(Delete)。 -
前面我们已经知道,调用SQLiteOpenHelper的getReadableDatabase( )或getWritable-
Database()方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个
SQLiteDatabase对象,借助这个对象就可以对数据进行CRUD操作了。 -
SQLiteDatabase对象提供了一个insert()方法,这个方法专门用于添加数据。、
参数:
-
第一个参数:表名,表示我们希望想拿张表添加数据
-
第二个参数:用于在未指定添加数据的情
况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传人null -
第三个参数:ContentValues对象,它提供了一系列的put方法重载 ,用于向ContentValues中添加数据。
-
-
修改主活动代码为:
package com.example.databasetest; import androidx.appcompat.app.AppCompatActivity; import android.content.ContentValues; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { protected MyDatabaseHelper dpHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dpHelper = new MyDatabaseHelper(this,"BookStore.dp", null, 2); Button createDatabase = (Button) findViewById(R.id.create_database); createDatabase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dpHelper.getWritableDatabase(); } }); Button addData = (Button) findViewById(R.id.add_data); addData.setOnClickListener(new View.OnClickListener() { //添加数据逻辑 @Override public void onClick(View view) { SQLiteDatabase db = dpHelper.getWritableDatabase(); //获取SQLiteDatabase对象 ContentValues values = new ContentValues(); //创建 ContentValues对象 values.put("name", "The Da Vinci Code"); //添加数据 values.put("author", "Dan Brown"); values.put("pages", 454); values.put("price", 16.96); db.insert("Book", null, values); //将数据存储进数据库 values.clear(); values.put("name", "The Da Lost Symbol"); values.put("author", "Dan BBrown"); values.put("pages", 510); values.put("price", 16.95); db.insert("Book", null, values); } }); } }
6.4.4 更新数据
-
概述:SQLiteDatabase中也提供了一个非常好用的update()方法,用于对数据进行更新,这个方法接收4
个参数,第一个参数和insert()方法一样,也是表名,在这里指定去更新哪张表里的数据。第二个参数是ContentValues对象,要把更新数据在这里组装进去。第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。 -
修改主活动代码:
package com.example.databasetest; import androidx.appcompat.app.AppCompatActivity; import android.content.ContentValues; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { protected MyDatabaseHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dbHelper = new MyDatabaseHelper(this, "BookStore.dp", null, 2); Button createDatabase = (Button) findViewById(R.id.create_database); createDatabase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dbHelper.getWritableDatabase(); } }); Button addData = (Button) findViewById(R.id.add_data); addData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("name", "The Da Vinci Code"); values.put("author", "Dan Brown"); values.put("pages", 454); values.put("price", 16.96); db.insert("Book", null, values); values.clear(); values.put("name", "The Da Lost Symbol"); values.put("author", "Dan BBrown"); values.put("pages", 510); values.put("price", 16.95); db.insert("Book", null, values); } }); Button button = (Button) findViewById(R.id.update_data); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SQLiteDatabase db = dbHelper.getWritableDatabase(); //获取SQLiteDatabase对象 ContentValues values = new ContentValues(); //创建ContentCValues对象 values.put("price", 10.99); // db.update("Book", values, "name = ?", new String[] {"The Da Vinci Code"}); //没看太懂 } }); } }
6.4.5 删除数据
-
概述:调用SQLiteDatabase中的delete 方法对数据库中内容进行删除,此方法传入三个参数,第一参数为表名,第二第三参数用于约束删除某一行或某几行的数据
Button delete = (Button) findViewById(R.id.Delete); delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SQLiteDatabase db = dbHelper.getWritableDatabase(); //获取SQLiteDatabase对像 db.delete("Book", "pages > ?", new String[] {"500"}); //约束条件为删除页数超过500页的书 } }); }
6.4.6 查询数据
-
概述:SQL的全称是Structured Query Language,翻译成中文就是结构化查询语言,SQlLiteDatabase中提供了一个query()方法,
-
参数:最短的一个方法重载也需要传人7个参数。那我们就先来看一下这7个
参数各自的含义吧。第一个参数不用说,当然还是表名,表示我们希望从哪张表中查询数据。第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列。第三、第四个参数用于约束查询某一行或某几行的数据,不指定则默认查询所有行的数据。第五个参数用于指定需要去group by
的列,不指定则表示不对查询结果进行group by操作。第六个参数用于对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤。第七个参数用于指定查询结果的排序方式,不指定
则表示使用默认的排序方式。
query()方法参数 | 对应SQL部分 | 描述 |
---|---|---|
table | from table_name | 指定查询的表明 |
columns | select column1, column2 | 指定查询的列表 |
selection | where column = value | 指定where的约束条件 |
selectionArgs | - | 为where中的占位符提供具体的值 |
groupBy | group by column | 指定需要的group by的列 |
having | having column = value | 对group by 后的结果进一步约束 |
orderBy | order by column1,column2 | 指定查询结果的排序方式 |
6.4.7 使用SQLite操作数据库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RFPJOvuQ-1631454087614)(C:\Users\过客\AppData\Roaming\Typora\typora-user-images\image-20210807114648012.png)]
6.5 使用LitePal操作数据库
6.5.1 LitePal简介
- 概述:LitePal是一款开源的Android数据库框架,它采用了对象关系映射( ORM )的模式,并将我
们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作。LitePal的项目主页上也有详细的使用文档,地址是: htps://github.com/LitePalFramework/LitePal
6.5.2 配置LitePal
配置流程;
-
添加依赖:
implementation 'org.litepal.guolindev:core:3.2.3'
-
在main下创建assets目录,然后再此目录下创建文件litepal.xml,修改其代码为:
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname vaule="People" /> <version value="1" /> <list> </list> <!--<dbname>标签用于指定数据库名 <version>标签用于指定版本号 <list>标签用于指定所有的映射模型--> </litepal>
解释:其中,标签用于指定数据库名,标签用于指定数据库版本号,
标签用于指定所有的映射模型 -
在注册表中添加如下代码:(将其添加在标签下)
android:name="org.litepal.LitePalApplication"
6.5.3 创建和升级数据库
创建数据库:
-
创建需要存储的数据类:(如此数据库添加book类,将想要存储的数据封装进类里面,为其添加get,set方法)
package com.example.litepaltest; public class Book { private int id; private String author; private double price; private int pages; private String name; private String press; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getPages() { return pages; } public void setPages(int pages) { this.pages = pages; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPress() { return press; } public void setPress(String press) { this.press = press; } }
-
修改litepal.xml文件代码为:
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="Book" /> <version value="2" /> <list> <mapping class="com.example.litepaltest.Book"/> //将类的映射添加进来 <mapping class="com.example.litepaltest.Category"/> </list> </litepal>
-
调用LitePal.getDatabase()方法创建数据库:
Button create = (Button) findViewById(R.id.Create); create.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { LitePal.getDatabase(); //点击按钮完成数据库的创建 } });
更新数据库:
-
若只修改某一类的部分数据,则在类中修改:
-
若添加新的数据表,则现创建数据类型,然后将其映射关系添加到litepal.xml下的标签下
创建类:
package com.example.litepaltest; public class Category { private int id; private String categoryName; private int categoryCode; public void setId(int id) { this.id = id; } public void setCategoryName(String categoryName) { this.categoryName = categoryName; } public void setCategoryCode(int categoryCode) { this.categoryCode = categoryCode; } }
添加映射:
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="Book" /> <version value="2" /> <list> <mapping class="com.example.litepaltest.Book"/> <mapping class="com.example.litepaltest.Category"/> //将新的表添加进list标签内 </list> </litepal>
-
最后记得将数据库的版本号加一,完成数据库的更新
6.5.4 使用LitePal添加数据
- 添加继承,让自己的数据类继承LitePalSupptor
public class Book extends LitePalSupport
- 创建所存储数据的对象实例,然后向此对象中添加所需存储的数据,最后调用save() 将数据添加至数据库:
Book book = new Book();
book.setName("The Da Vinci Code");
book.setAuthor("Dan brown");
book.setPages(454);
book.setPrice(16.96);
book.setPress("UnKnow");
book.save();
6.5.5 使用LitePal更新数据
-
通过获取对象实例类对所存储的数据进行更新:(可通过LitePal提供的查询API查询出来对象实例,然后对其修改在进行存储,实现数据的更新)
Button upData = (Button) findViewById(R.id.Update); upData.setOnClickListener(view -> { Book book = new Book(); //只能对一存储的对像实例进行操作 book.setName("The Lost Symbol"); book.setAuthor("Dan Brown"); book.setPages(510); book.setPrice(19.96); book.setPress("UnKnow"); book.save(); //对此对象进行存储 book.setPrice(10.99); book.save(); //由于此对象已经被存储过了,所以此save只会对此对象的数据进行修改 });
-
通过调用updateAll()方法对数据进行更新:
Button upData = (Button) findViewById(R.id.Update); upData.setOnClickListener(view -> { Book book = new Book(); //创建Book对象 book.setPrice(16.95); book.setAuthor("Dan Brown"); book.setPress("Anchor"); //设置想要更新的数据 book.updateAll("name = ?","The Lost Symbol"); //调用方法对数据进行更新,添加约束条件,此约束条件为书名为The Lost Symbol的对象,执行结果为会将所有书名为此的数据的那三条数据更新 });
-
将数据更新为默认值的操作,LitePal统一提供了一个setToDefault()方法,传入响应的列名即可
Book book = new Book(); book.setToDefault("pages"); book.updateAll();
这段代码的意思是,将所有书的页数都更新为0,因为updateAll()方法中没有指定约束件,因此更新操作对所有数据都生效了。
6.5.6 使用LitePal删除数据
-
通过获取存储的数据对象实例,然后调用delete()方法类删除数据
-
使用deleteAll()方法类删除数据:使用LitePal.deleteAll()方法
Button delData = (Button) findViewById(R.id.Delete); delData.setOnClickListener(View -> { LitePal.deleteAll(Book.class, "price < ?", "16.96"); //约束条件为价格低于16.96的书 });
3 若不指定约束条件则删除全部数据
6.5.7 使用LitePal查询数据
-
LitePal调用
findAll()
方法,返回一个List集合,将数据库中此表的数据全部拿出Button query = (Button) findViewById(R.id.Query); query.setOnClickListener(View -> { List<Book> books = LitePal.findAll(Book.class); for(Book book:books) { Log.d("MainActivity", "book name is " + book.getName()); Log.d("MainActivity", "book author is " + book.getAuthor()); Log.d("MainActivity", "book pages is " + book.getPages()); Log.d("MainActivity", "book price is " + book.getPrice()); Log.d("MainActivity", "book press is " + book.getPress()); } });
-
LitePal的查询API:
-
查询Book表中的第一条数据:
Book firstBook = LitePal.findFirst(Book.class);
-
查询Book表中的最后一条数据
Book lastBook = LitePal.findLast(Book.class);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zcctXnaj-1631454087616)(C:\Users\过客\AppData\Roaming\Typora\typora-user-images\image-20210808115747983.png)]
-