第六章 数据存储权方案——详解持久化技术

6.1 持久化技术简介

  1. 概述:Android 系统中主要提供了3种方式用于简单地实现数据持久化功能,即文件存储、SharedPreference存储以及数据库存储。当然,除了这3种方式之外,你还可以将数据保存在手机的SD卡中,不过使用文件、SharedPreference 或数据库来保存数据会相对更简单一些,
    而且比起将数据保存在SD卡中会更加地安全。

6.2 文件存储

6.2.1 将文件存储到文件中

  1. Context类中提供了一个openFileOutput()方法,这个方法接收两个参数,第一个参数是文件名,在文件创建的时候使用的就是这个名称,注意这
    里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data//files/目录下的。第二个参数是文件的操作模式,主要有两种模式可选,MODE_ PRIVATE
    和MODE APPEND。其中MODE_ PRIVATE 是默认的操作模式,表示当指定同样文件名的时候,
    所写入的内容将会覆盖原文件中的内容,而MODE_ APPEND 则表示如果该文件已存在,就往文
    件里面追加内容,不存在就创建新文件。

  2. 给主活动界面添加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"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/type_something_here"android:id="@+id/edit"/></LinearLayout>
    
  3. 修改主活动代码,使其再销毁活动时实现数据的存储:

    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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);edit = (EditText) findViewById(R.id.edit);}@Overrideprotected 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 从文件中读取数据

  1. 概述:Context 类中还提供了一个openFileInput()方法,用于从文件中读取数据。这个方法要比openFile0utput()简单一些,它只接收一个参数,即要读取的文件名,然后系统会自动到/data/data//files/目录下去加载这个文件,并返回一个
    FileInputStream对象,得到了这个对象之后再通过Java流的方式就可以将数据读取出来了。

  2. 修改主活动代码,编写数据写入方法

    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;@Overrideprotected 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();}}@Overrideprotected 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存储

  1. 概述:不同于文件的存储方式,SharedPreferences是使用键值对的方式来存储数据的。当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过
    **这个键把相应的值取出来。**而且SharedPreferences 还支持多种不同的数据类型存储,存什么数据类型就拿出什么数据类型

6.3.1 将数据存储到SharedPreferences中

  1. 概述:使用SharedPreference来存储数据,首先的获取到SharedPreferences对象。Android提供了3种方法用于得到SharedPreferences对象。

  2. 三种获得SharedPreferences对象的方式:

    1. Context类中的getSharedPreferences()方法:

      此方法接收两个参数,第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个SharedPreferences 文件都是存放在/data/data//shared_ _prefs/
      目录下
      的。第二个参数用于指定操作模式,目前只有MODE _PRIVATE这一种模式可选,它是默认的操作模式,和直接传入0效果是相同的,表示只有当前的应用程序才可以对这个
      SharedPreferences文件进行读写。

    2. Activity类中的getPreferences()方法:

      这个方法和Context中的getSharedPreferences( )方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为SharedPreferences的文件名。

    3. PreferenceManager类中的getDefaultSharedPreferences()方法:

      这是一个静态方法,它接收一个Context 参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences 文件。得到了SharedPreferences 对象之后,就可以开始向SharedPreferences文件中存储数据了,主要可以分为3步实现。

  3. 使用步骤:

    • 调用SharedPreferences对象的edit()方法来获取一个SharedPreferences . Editor对象

    • 向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用
      putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。

    • 调用apply()方法将添加的数据提交,从而完成数据存储操作。

  4. 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"><Buttonandroid: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 {@Overrideprotected 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() {@Overridepublic 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方法将添加的数据提交,完成数据的存储}});}
}
  1. 补充:此方式类似于map集合的存储的方式,它只会为唯一键匹配唯一值,相同键会在第二添加数据时覆盖第一次添加的数据,键相同时如果类型不一样,下面出现的将对上面出现的类型进行覆盖

6.3.2 从SharedPreferences中读取数据

  1. 为主活动添加一个按钮并为其设置带年纪事件:

    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";@Overrideprotected 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() {@Overridepublic 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() {@Overridepublic 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 实现记住密码功能

  1. 新控件,CheckBox:这是一个复选框控件,用户可以通过点击的方式来进行选中或取消。

    <LinearLayoutandroid: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" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/remember_password"android:textSize="18sp" /></LinearLayout>
    
  2. 再主活动设置记住密码的处理逻辑:(先判断是否点击爆粗密码的复选框,点击则通过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;@Overrideprotected 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() {@Overridepublic 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 创建数据库

  1. 概述:Android为了让我们能够更加方便地管理数据库,专广]提供了一个SQLiteOpenHelper帮助类
    借助这个类就可以非常简单地对数据库进行创建和升级。

  2. SQLiteOpenHelper类:此类为一个抽象类,含有两个抽象方法,onCreatae()和onUpgrade()

    1. 实例方法:两方法都可以创建或者打开一个现有数据库(存在则打开,否则则创建),并返回一个可对数据库进行读写操作的对象。不同:

      1. getReadableDatabase(): 当数据库不可写入时,将以只读的方式打开数据库
      2. getWritableDatabase(): 当数据库不可写入时,此方法将抛出异常
  3. 构造方法参数说明:

    1. SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可
      这个构造方法中接收4个参数,第一个参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的Cursor, 一般都是传入null第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper 的实例之后,
  4. 创建数据库需要创建表:需要使用建表语句

    ![

    ](C:\Users\过客\AppData\Roaming\Typora\typora-user-images\image-20210805104809457.png)

  5. SQLite的数据类型很简单,只有四种:

    1. integer 表示整型
    2. real表示浮点型
    3. text表示文本类型
    4. blob表示二进制类型
  6. 代码实现:(先创建自己的帮助类,让其继承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;}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(CREATE_BOOK);    //将建表语句定义成为一个字符串常量,SQLiteDatabase的execSQL()方法Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();  //弹窗提示}@Overridepublic void onUpgrade(SQLiteDatabase db, int olderVersion, int newVersion) {}
    }
  7. 创建数据库:

    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;@Overrideprotected 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() {@Overridepublic void onClick(View view) {dpHelper.getWritableDatabase();        //创建数据库}});}
    }
    

6.4…2 升级数据库

  1. 概述:通过onUpgrade()方法对数据库进行升级

  2. 修改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;}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(CREATE_BOOK);db.execSQL(CREATE_CATEGORY);Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();}@Overridepublic void onUpgrade(SQLiteDatabase db, int olderVersion, int newVersion) {  //执行更细数据库方法db.execSQL("drop table if exists Book");   //判断是否存在此表,存在则删除db.execSQL("drop table if exists Category");onCreate(db);  //上面不删除则此处抛异常}
    }
  3. 当主活动中方法执行哪里的版本号大于之前的版本号,则会执行帮助类中的onUpgrade方法

6.4.3 添加数据

  1. 概述:其实我们可以对数据进行的操作无非有4种,即CRUD。其中C代表添加(Create), R代
    表查询( Retrieve), U代表更新( Update), D代表删除(Delete)。

  2. 前面我们已经知道,调用SQLiteOpenHelper的getReadableDatabase( )或getWritable-
    Database()方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个
    SQLiteDatabase对象,借助这个对象就可以对数据进行CRUD操作了。

  3. SQLiteDatabase对象提供了一个insert()方法,这个方法专门用于添加数据。、

    参数:

    1. 第一个参数:表名,表示我们希望想拿张表添加数据

    2. 第二个参数:用于在未指定添加数据的情
      况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传人null

    3. 第三个参数:ContentValues对象,它提供了一系列的put方法重载 ,用于向ContentValues中添加数据。

  4. 修改主活动代码为:

    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;@Overrideprotected 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() {@Overridepublic void onClick(View view) {dpHelper.getWritableDatabase();}});Button addData = (Button) findViewById(R.id.add_data);addData.setOnClickListener(new View.OnClickListener() {       //添加数据逻辑@Overridepublic 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 更新数据

  1. 概述:SQLiteDatabase中也提供了一个非常好用的update()方法,用于对数据进行更新,这个方法接收4
    个参数,第一个参数和insert()方法一样,也是表名,在这里指定去更新哪张表里的数据。第二个参数是ContentValues对象,要把更新数据在这里组装进去。第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行

  2. 修改主活动代码:

    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;@Overrideprotected 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() {@Overridepublic void onClick(View view) {dbHelper.getWritableDatabase();}});Button addData = (Button) findViewById(R.id.add_data);addData.setOnClickListener(new View.OnClickListener() {@Overridepublic 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() {@Overridepublic 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 删除数据

  1. 概述:调用SQLiteDatabase中的delete 方法对数据库中内容进行删除,此方法传入三个参数,第一参数为表名,第二第三参数用于约束删除某一行或某几行的数据

     Button delete = (Button) findViewById(R.id.Delete);delete.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {SQLiteDatabase db = dbHelper.getWritableDatabase();       //获取SQLiteDatabase对像db.delete("Book", "pages > ?", new String[] {"500"});  //约束条件为删除页数超过500页的书}});}
    

6.4.6 查询数据

  1. 概述:SQL的全称是Structured Query Language,翻译成中文就是结构化查询语言,SQlLiteDatabase中提供了一个query()方法,

  2. 参数:最短的一个方法重载也需要传人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简介

  1. 概述:LitePal是一款开源的Android数据库框架,它采用了对象关系映射( ORM )的模式,并将我
    们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作。LitePal的项目主页上也有详细的使用文档,地址是: htps://github.com/LitePalFramework/LitePal

6.5.2 配置LitePal

配置流程;

  1. 添加依赖:

        implementation 'org.litepal.guolindev:core:3.2.3'
    
  2. 在main下创建assets目录,然后再此目录下创建文件litepal.xml,修改其代码为:

    <?xml version="1.0" encoding="utf-8"?>
    <litepal><dbname vaule="People" /><version value="1" /><list></list><!--<dbname>标签用于指定数据库名 <version>标签用于指定版本号 <list>标签用于指定所有的映射模型--></litepal>

    解释:其中,标签用于指定数据库名,标签用于指定数据库版本号,
    标签用于指定所有的映射模型

  3. 在注册表中添加如下代码:(将其添加在标签下)

    android:name="org.litepal.LitePalApplication"
    

6.5.3 创建和升级数据库

创建数据库:

  1. 创建需要存储的数据类:(如此数据库添加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;}
    }
  2. 修改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>
  3. 调用LitePal.getDatabase()方法创建数据库:

    Button create = (Button) findViewById(R.id.Create);create.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {LitePal.getDatabase();       //点击按钮完成数据库的创建}});
    

更新数据库:

  1. 若只修改某一类的部分数据,则在类中修改:

  2. 若添加新的数据表,则现创建数据类型,然后将其映射关系添加到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>
  3. 最后记得将数据库的版本号加一,完成数据库的更新

6.5.4 使用LitePal添加数据

  1. 添加继承,让自己的数据类继承LitePalSupptor
public class Book extends LitePalSupport
  1. 创建所存储数据的对象实例,然后向此对象中添加所需存储的数据,最后调用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更新数据

  1. 通过获取对象实例类对所存储的数据进行更新:(可通过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只会对此对象的数据进行修改});
    
  2. 通过调用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的对象,执行结果为会将所有书名为此的数据的那三条数据更新});
    
  3. 将数据更新为默认值的操作,LitePal统一提供了一个setToDefault()方法,传入响应的列名即可

        Book book = new Book();book.setToDefault("pages");book.updateAll();
    

    这段代码的意思是,将所有书的页数都更新为0,因为updateAll()方法中没有指定约束件,因此更新操作对所有数据都生效了。

6.5.6 使用LitePal删除数据

  1. 通过获取存储的数据对象实例,然后调用delete()方法类删除数据

  2. 使用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查询数据

  1. 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());}});
    
  2. LitePal的查询API:

    1. 查询Book表中的第一条数据:

      Book firstBook = LitePal.findFirst(Book.class);

    2. 查询Book表中的最后一条数据

      Book lastBook = LitePal.findLast(Book.class);

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zcctXnaj-1631454087616)(C:\Users\过客\AppData\Roaming\Typora\typora-user-images\image-20210808115747983.png)]

Android学习笔记(6)——详解持久化技术相关推荐

  1. IOS开发学习笔记-----UILabel 详解

    IOS开发学习笔记-----UILabel 详解 01 //创建uilabel 02 UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMa ...

  2. wringPi 初始化GPIO 为上拉_敏矽微电子Cortex-M0学习笔记04-GPIO详解及应用实例

    前面我们已经对敏矽微电子的基于cortex m0内核的ME32F030R8T6的基本功能做了介绍,然后详细讲解了开发环境MDK的安装,pack包的安装,工程的建立及程序的仿真,紧接着讲解了ME32F0 ...

  3. python学习笔记 正则表达式 详解2

    python学习笔记 正则表达式 详解 行定位符 行定位符就是用来描述子串的边界."^"表示行的开始:"$"表示行的结尾 ^tm:匹配以子串tm的开始位置是行头 ...

  4. 第一行代码学习笔记第六章——详解持久化技术

    知识点目录 6.1 持久化技术简介 6.2 文件存储 * 6.2.1 将数据存储到文件中 * 6.2.2 从文件中读取数据 6.3 SharedPreferences存储 * 6.3.1 将数据存储到 ...

  5. 第二行代码学习笔记——第六章:数据储存全方案——详解持久化技术

    本章要点 任何一个应用程序,总是不停的和数据打交道. 瞬时数据:指储存在内存当中,有可能因为程序关闭或其他原因导致内存被回收而丢失的数据. 数据持久化技术,为了解决关键性数据的丢失. 6.1 持久化技 ...

  6. 关于ClassLoader的学习笔记,详解版

    ClassLoader 详解 ClassLoader 做什么的? 延迟加载 各司其职 ClassLoader 传递性 双亲委派 Class.forName 自定义加载器 Class.forName v ...

  7. 第6章 数据存储全方案,详解持久化技术

    所有的App都可以说是与数据打交道的,离开数据它们什么都不是.那么平时我们怎么存储一些关键的数据呢? 1 持久化技术简介 数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关 ...

  8. android学习日记——PreferenceActivity详解

    PreferenceActivity详解 何为PreferenceActivity 以下为官方解释: This is the base class for anactivity to show a h ...

  9. DNS 学习笔记之三- 详解DNS的资源记录

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />       最 ...

最新文章

  1. ActiveMQ消息的延时和定时投递
  2. 运行 OpenCV-Python-Toturial-中文版 遇到的一些错误问题
  3. shell中的各种括号的使用方法
  4. C++对象内存布局--③测试多继承中派生类的虚函数在哪一张虚函数表中
  5. SorterBot-第1部分
  6. java 开发帮助_java的简单编程请帮助
  7. java循环的嵌套执行
  8. Nhibernate代码自动生成工具[转]
  9. 详解自然语言处理5大语义分析技术及14类应用(建议收藏)
  10. 基于bootstrap_登陆页面
  11. 如何阅读Cookbook技术书——如果我要把一本几百上千页的书从头读到尾,应该怎样有效阅读。...
  12. mybatis的set标签
  13. updatepanel失效怎么办_[转]jquery与updatepanel二次失效问题解决方案-阿里云开发者社区...
  14. 二战十大致命武器之“喷火”式战斗机
  15. 计算机基础表格制作教学设计,word中表格制作教学设计精选
  16. 使用 {}.format 对字符串进行格式(一)
  17. 团队组成五个基本要素_团队管理的五个基本要素
  18. Hyper-V虚拟化——在Hyper-V上创建虚拟服务器
  19. Arduino UNO u8glib显示中文-亲测可用
  20. 每日英语:China's Red Cross Tries to Rebuild After Self-Inflicted Disaster

热门文章

  1. 小米粥煮多久才好吃 小米粥怎么煮才有营养
  2. 甘南佛教圣地----拉卜楞寺参访 2018年5月21日
  3. 如何查看MySQL数据库状态及信息(内存、数据库、编码格式、表、列、索引等)
  4. 一张图看懂DNS域名解析全过程
  5. STM32串口接收粉尘传感器数据
  6. 分治法--棋盘覆盖问题
  7. mysql having in_mysql:having 用法
  8. 2021年12月2日
  9. 商场三十六计——第34计 “反间计”
  10. 多闪删掉的作品怎么恢复_快手删除的作品怎么恢复