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

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"
    >
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/type_something_here"
        android:id="@+id/edit"/>

</LinearLayout>
  1. 修改主活动代码,使其再销毁活动时实现数据的存储:
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 从文件中读取数据
  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;

    @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存储

  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步实现。
  1. 使用步骤:
  • 调用SharedPreferences对象的edit()方法来获取一个SharedPreferences . Editor对象
  • 向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用
    putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。
  • 调用apply()方法将添加的数据提交,从而完成数据存储操作。
  1. 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方法将添加的数据提交,完成数据的存储
            }
        });
    }
}
  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";

    @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 实现记住密码功能
  1. 新控件,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>
  1. 再主活动设置记住密码的处理逻辑:(先判断是否点击爆粗密码的复选框,点击则通过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 创建数据库
  1. 概述:Android为了让我们能够更加方便地管理数据库,专广]提供了一个SQLiteOpenHelper帮助类
    借助这个类就可以非常简单地对数据库进行创建和升级。
  2. SQLiteOpenHelper类:此类为一个抽象类,含有两个抽象方法,onCreatae()和onUpgrade()
  1. 实例方法:两方法都可以创建或者打开一个现有数据库(存在则打开,否则则创建),并返回一个可对数据库进行读写操作的对象。不同:
  1. getReadableDatabase(): 当数据库不可写入时,将以只读的方式打开数据库
  2. getWritableDatabase(): 当数据库不可写入时,此方法将抛出异常
  1. 构造方法参数说明:
  1. SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可
    这个构造方法中接收4个参数,第一个参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的Cursor, 一般都是传入null第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper 的实例之后,
  1. 创建数据库需要创建表:需要使用建表语句
    ![
    ](C:\Users\过客\AppData\Roaming\Typora\typora-user-images\image-20210805104809457.png)
  2. SQLite的数据类型很简单,只有四种:
  1. integer 表示整型
  2. real表示浮点型
  3. text表示文本类型
  4. blob表示二进制类型
  1. 代码实现:(先创建自己的帮助类,让其继承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) {

    }
}
  1. 创建数据库:
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 升级数据库
  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;
    }

    @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);	//上面不删除则此处抛异常
    }
}
  1. 当主活动中方法执行哪里的版本号大于之前的版本号,则会执行帮助类中的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中添加数据。
  1. 修改主活动代码为:
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 更新数据
  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;

    @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 删除数据
  1. 概述:调用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 查询数据
  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'
  1. 在main下创建assets目录,然后再此目录下创建文件litepal.xml,修改其代码为:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname vaule="People" />

    <version value="1" />

    <list>
    </list>

    <!--<dbname>标签用于指定数据库名 <version>标签用于指定版本号 <list>标签用于指定所有的映射模型-->

</litepal>

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

  1. 在注册表中添加如下代码:(将其添加在标签下)
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;
    }
}
  1. 修改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>
  1. 调用LitePal.getDatabase()方法创建数据库:
Button create = (Button) findViewById(R.id.Create);
        create.setOnClickListener(new View.OnClickListener() {
            @Override
            public 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>
  1. 最后记得将数据库的版本号加一,完成数据库的更新
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只会对此对象的数据进行修改
    });
  1. 通过调用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的对象,执行结果为会将所有书名为此的数据的那三条数据更新
    });
  1. 将数据更新为默认值的操作,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());
        }
    });
  1. LitePal的查询API:
  1. 查询Book表中的第一条数据:

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

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

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

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