简单书籍信息管理app(安卓+SQLite)

前言

本程序是对于B站视频【android-sqlite数据库基本操作|快速入门|增删改查|基础】讲解的复现与总结。原视频链接如下http:// https://www.bilibili.com/video/BV1YY4y1M77G/?share_source=copy_web&vd_source=225ab65670127697252f369e1861a02c

本程序实现了自建安卓数据库,并且在数据库中可以执行增、删、改、查,等基本操作。

程序除了前端UI代码之外还包含MainActivity,MyDataHelper,BookModel,UpdateActivity这四个后端项目文件。

MainActivity 负责显示所有书籍列表、添加新书籍和处理每本书的删除和修改操作。

MyDataHelper 是数据库帮助类,处理数据库的创建、表的操作(增、删、改、查)。

BookModel 是书籍模型类,定义了书籍的属性和方法。

UpdateActivity 用于修改书籍信息,从 MainActivity 接收书籍信息,更新后保存到数据库。

后文也会分别对这些活动进行介绍。

UI

MainActivity的界面

除了常见的Plain Text和Button之外,我还使用了ListView。ListView用于展示添加的书籍信息,并且可以对信息进行修改或者删除。

更多关于ListView组件的使用方法可以参考官方文档

https://developer.android.com/reference/android/widget/ListView

代码如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/add_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:ems="10"
        android:hint="标题"
        android:inputType="text"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/add_author"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:ems="10"
        android:hint="作者"
        android:inputType="text"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/add_title" />

    <Button
        android:id="@+id/add_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="添加"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/add_author" />

    <ListView
        android:id="@+id/view_all"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="30dp"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="30dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/add_btn" />
</androidx.constraintlayout.widget.ConstraintLayout>

UpdateActivity的界面

这个界面是在MainActivity中点击ListView里的任一书籍信息,即可跳转到此。

代码如下 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".UpdateActivity">

    <EditText
        android:id="@+id/update_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:ems="10"
        android:hint="标题"
        android:inputType="text"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/update_author"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:ems="10"
        android:hint="作者"
        android:inputType="text"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/update_title" />

    <Button
        android:id="@+id/update_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="确定修改"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/update_author" />
</androidx.constraintlayout.widget.ConstraintLayout>

功能

BookModel

这个活动首先利用构造函数对新的数据进行存储

public BookModel(Integer id, String title, String author) {
        this.id = id;
        this.title = title;
        this.author=author;
    }

然后是重写toString方法,让它返回书籍在数据库中存储的id,书名和作者名,并且方便输出

 @Override
    public String toString() {
        return "BookModel{" +
                "书籍id=" + id +
                ", 书名='" + title + "'" +
                ", 作者='" + author + "'" +
                "}";
    }

最后是通过创建一系列get方法可以精准获取对应的数据

 public Integer getId() {
        return id;
    }
 public String getTitle() {
        return title;
    }
 public String getAuthor() {
        return author;
    }

完成的代码如下

package com.example.sqlite_test;

public class BookModel {
    private Integer id;
    private String title;
    private String author;

    //构造函数,初始化书的ID,题目和作者
    public BookModel(Integer id, String title, String author) {
        this.id = id;
        this.title = title;
        this.author = author;
    }

    //默认的 toString 方法返回的是对象的类名和内存地址,这对于理解对象的内容没有帮助。
    //重写 toString 方法后,可以输出书籍的 ID、标题和作者等详细信息,使对象更易于理解和阅读。
    @Override
    public String toString() {
        return "BookModel{" +
                "书籍id=" + id +
                ", 书名='" + title + "'" +
                ", 作者='" + author + "'" +
                "}";
    }

    public Integer getId() {
        return id;
    }
    public String getTitle() {
        return title;
    }
    public String getAuthor() {
        return author;
    }

}

MyDataHelper

此活动通过继承SQLiteOpenHelper类实现了对于数据库的增删改查,或者说是创建了增删改查的方法,以便在之后使用。

首先来介绍SQLiteOpenHelper在这里发挥的作用

  • 管理数据库连接:

    • SQLiteOpenHelper通过内部维护的 SQLiteDatabase  对象,提供了对数据库的读写访问。它会管理数据库连接的打开和关闭,确保数据库连接的安全和高效使用。

    • SQLiteDatabase 类用于执行 SQL 语句以管理数据库。通过 SQLiteOpenHelper 提供的方法(如 getWritableDatabase() 和 getReadableDatabase()),可以获得 SQLiteDatabase 的实例。

      SQLiteDatabase 提供了多种方法用于执行 SQL 操作,如插入、删除、更新和查询。

  • 简化数据库创建和升级:

    • 通过 onCreate 方法和 onUpgrade 方法,开发者可以很方便地定义数据库的创建和升级逻辑,而不需要手动编写大量的 SQL 语句来管理数据库结构的变化。
    • onCreate(SQLiteDatabase db):当数据库第一次被创建时调用。在这里你可以执行创建数据库表的 SQL 语句。
    • onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):当数据库需要升级时调用(比如增加或修改表结构)。在这里你可以执行修改数据库结构的 SQL 语句。
  • 封装数据库操作:

    • SQLiteOpenHelper提供了方便的 API,简化了常见的数据库操作,例如插入、删除、更新和查询数据。

此方法继承父类之后需要重写父类中的方法

    public MyDataHelper(@Nullable Context context) {
//        这是调用 SQLiteOpenHelper 的构造函数,初始化一个 SQLite 数据库帮助类。
//        context: 应用的上下文,用于访问应用的资源和类。
//        "books.db": 数据库的名称。这个数据库文件将在应用的默认数据库路径中创建。如果文件不存在,它将被创建;如果文件已经存在,它将被打开。
//        null: CursorFactory,通常设置为 null。如果提供了一个 CursorFactory,它将用于创建游标对象,通常我们不需要自定义游标,所以传 null。
//        1: 数据库的版本号。数据库的版本号用于管理数据库的升级和降级。当版本号发生变化时,onUpgrade 或 onDowngrade 方法会被调用,以处理数据库的结构变化。
        super(context, "books.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        //创建表的sql语句,创建 book 表。
        //表包含三个列:id(自增主键)、title(文本)和 author(文本)。
        String sql= "CREATE TABLE " + TABLE_NAME + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_TITLE + " TEXT," + COLUMN_AUTHOR + " TEXT)";
        sqLiteDatabase.execSQL(sql);//使用 execSQL 方法执行创建表的 SQL 语句。
    }
    //数据库更新时调用
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        // 该方法用于数据库版本升级时调用,这里没有实现具体的逻辑
    }

接下来是创建增删改查数据库内容的功能

//添加一条书籍记录
    public String addOne(BookModel bookModel)
    {
        ContentValues cv=new ContentValues();
        //使用 ContentValues 对象 cv 存储书籍的 title 和 author
        cv.put(COLUMN_AUTHOR,bookModel.getAuthor());
        cv.put(COLUMN_TITLE,bookModel.getTitle());
        SQLiteDatabase sqLiteDatabase=this.getWritableDatabase();
        //TABLE_NAME: 表示要插入记录的表名,这里是 "book" 表。
        //COLUMN_AUTHOR: 通常用来指定一个列名,当 ContentValues 为空时,该列会被插入空值。我们使用了 ContentValues 来指定要插入的列和值。
        //cv: 一个 ContentValues 对象,包含要插入的列名和对应的值。
        long insert=sqLiteDatabase.insert(TABLE_NAME,null,cv);//使用 insert 方法将 cv 中的数据插入到 book 表中。
        //如果插入成功,insert 变量将返回新插入记录的行ID;如果失败,则返回 -1。
        if(insert==-1)
        {
            return "fail";
        }
        sqLiteDatabase.close();
        return "success";
    }
    //删除一条书籍记录
    public String deleteOne(BookModel bookModel)
    {
        SQLiteDatabase sqLiteDatabase=this.getWritableDatabase();
        //TABLE_NAME: 表示要删除记录的表名,这里是 "book" 表。
        //COLUMN_ID + "=?": WHERE 子句,指定删除条件,这里是 id 列等于某个值。
        //new String[]{String.valueOf(bookModel.getId())}: WHERE 子句中的参数数组,用于替换 ?,这里是书籍的 id。
        int delete=sqLiteDatabase.delete(TABLE_NAME,COLUMN_ID+ "=?",new String[]{String.valueOf(bookModel.getId())});//使用 delete 方法根据书籍的 id 删除相应的记录
        sqLiteDatabase.close();
        //如果删除成功,delete 变量将返回删除的行数;如果失败,则返回0
        if(delete==0)
        {
            return "fail";
        }
        return "success";
    }
    //更新一条书籍记录
    public String updateOne(BookModel bookModel)
    {
        ContentValues cv=new ContentValues();
        cv.put(COLUMN_AUTHOR,bookModel.getAuthor());
        cv.put(COLUMN_TITLE,bookModel.getTitle());
        SQLiteDatabase sqLiteDatabase=this.getWritableDatabase();
//        TABLE_NAME: 表示要更新记录的表名,这里是 "book" 表。
//        cv: 一个 ContentValues 对象,包含要更新的列名和对应的新值。
//        COLUMN_ID + "=?": WHERE 子句,指定更新条件,这里是 id 列等于某个值。
//        new String[]{String.valueOf(bookModel.getId())}: WHERE 子句中的参数数组,用于替换 ?,这里是书籍的 id。
        int update = sqLiteDatabase.update(TABLE_NAME, cv, COLUMN_ID + "=?", new String[]{String.valueOf(bookModel.getId())});//使用 update 方法根据书籍的 id 更新相应的记录。
        //如果更新成功,update 变量将返回更新的行数;如果失败,则返回 0。
        if(update==0)
        {
            return "fail";
        }
        return "success";
    }

请注意,本活动一开始进行过常量声明,将数据库所用到的例如book,id,title,author都已经改成常量名。

 public static final String TABLE_NAME = "book";//表名常量
 public static final String COLUMN_ID = "id";//id列名常量
 public static final String COLUMN_TITLE = "title";//书名列名常量
 public static final String COLUMN_AUTHOR = "author";//作者列名常量

最后,从数据库中获取所有书籍信息,并将它们转换为BookModel对象的列表,为此创建一个函数。

public List<BookModel> getAll()
    {
        List<BookModel> list=new ArrayList<>();//声明了一个 List<BookModel> 类型的列表 list,用于存储从数据库中检索到的书籍记录。

        String sql="SELECT * FROM "+TABLE_NAME;//定义一个 SQL 查询字符串 sql,用于从数据库中的表(TABLE_NAME,即 book 表)中选择所有的记录。

        SQLiteDatabase sqLiteDatabase=this.getReadableDatabase();//调用 getReadableDatabase 方法获取一个可读的 SQLiteDatabase 对象 sqLiteDatabase,用于执行读取操作。

        Cursor cursor= sqLiteDatabase.rawQuery(sql,null);//使用 sqLiteDatabase 对象执行前面定义的 SQL 查询,并返回一个 Cursor 对象 cursor,该对象指向查询结果集。

        //获取每列的索引值(COLUMN_ID、COLUMN_TITLE 和 COLUMN_AUTHOR),这些列对应数据库表中的列(即 id、title 和 author)。
        //通过列名获取该列的索引。如果列名不存在,返回 -1。
        int idIndex=cursor.getColumnIndex(COLUMN_ID);
        int titleIndex=cursor.getColumnIndex(COLUMN_TITLE);
        int authorIndex=cursor.getColumnIndex(COLUMN_AUTHOR);

        //使用 while 循环遍历 Cursor 对象中的每一条记录。moveToNext 方法将 Cursor 移动到下一行,如果有更多行则返回 true,否则返回 false
        //在循环体内,通过 cursor 获取当前记录的 id、title 和 author 的值,并创建一个新的 BookModel 对象 bookModel。
        //将创建的 BookModel 对象添加到 list 中。
        while(cursor.moveToNext())
        {
            BookModel bookModel=new BookModel(cursor.getInt(idIndex),cursor.getString(titleIndex),cursor.getString(authorIndex));
            list.add(bookModel);
        }

        cursor.close();
        sqLiteDatabase.close();
        return list;
    }

上述代码中,多次用到了 SQLiteOpenHelper类中的getWritableDatabase和getReadableDatabase方法,还有一个没有用到但是和它俩长得很像的一个方法getDatabaseName;另外还有Cursor。这里说明一下个人的理解,同时也会贴出官方文档的介绍:

getWritableDatabase()

功能:

  • getWritableDatabase()方法用于以读写模式打开数据库。如果数据库不存在,则会创建一个新的数据库。此方法返回一个可供读写的 SQLiteDatabase 对象。

作用:

  • 该方法主要用于需要对数据库进行写操作(如插入、更新、删除)的场景。

示例:

SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
long insert = sqLiteDatabase.insert(TABLE_NAME, null, cv);
sqLiteDatabase.close();

 

getReadableDatabase()

功能:

  • getReadableDatabase() 方法用于以只读模式打开数据库。如果数据库不存在,则会创建一个新的数据库。此方法返回一个只读的 SQLiteDatabase 对象。

作用:

  • 该方法主要用于需要对数据库进行读取操作(如查询)的场景。当不需要对数据库进行写操作时,可以使用该方法以保证数据库的安全性和性能。

示例:

SQLiteDatabase sqLiteDatabase = this.getReadableDatabase();
Cursor cursor = sqLiteDatabase.rawQuery(sql, null);

这里官方文档也给出提示,要记得写上close方法来处理缓存 。

getDatabaseName()

功能:

  • getDatabaseName() 方法返回当前 SQLiteOpenHelper 对象管理的数据库的名称。

作用:

  • 该方法主要用于获取数据库的名称,便于调试和日志记录等用途。

示例:

String dbName = this.getDatabaseName();

Cursor

Cursor 是 Android 提供的一个接口,用于表示从数据库查询返回的结果集。它提供了一系列方法,用于访问和遍历结果集中的数据。

Cursor 的常用方法

  1. 导航方法:

    • moveToFirst(): 移动到结果集的第一行。
    • moveToLast(): 移动到结果集的最后一行。
    • moveToNext(): 移动到结果集的下一行。
    • moveToPrevious(): 移动到结果集的上一行。
    • moveToPosition(int position): 移动到结果集的指定行。
  2. 数据获取方法:

    • getInt(int columnIndex): 获取指定列的整数值。
    • getString(int columnIndex): 获取指定列的字符串值。
    • getDouble(int columnIndex): 获取指定列的双精度浮点值。
    • getColumnIndex(String columnName): 获取指定列名的索引。
  3. 资源管理方法:

    • close(): 关闭 Cursor,释放资源。
    • isClosed(): 判断 Cursor 是否已经关闭。

Cursor 的使用步骤

  1. 执行查询并获取 Cursor 对象:

    使用 SQLiteDatabase 的查询方法(如 queryrawQuery)执行查询,并返回一个 Cursor 对象。
  2. 导航和获取数据:

    使用导航方法定位到特定行,然后使用数据获取方法提取数据。
  3. 关闭 Cursor

    使用完 Cursor 后,调用 close 方法关闭它,防止资源泄漏。

 示例:

// 示例中,Cursor 用于遍历查询结果,并从每一行中提取数据。
// 获取可读的数据库对象
SQLiteDatabase db = myDataHelper.getReadableDatabase();

// 执行查询,获取包含结果的 Cursor 对象
Cursor cursor = db.rawQuery("SELECT * FROM book", null);

// 使用 while 循环遍历 Cursor 中的每一行
while (cursor.moveToNext()) {
    // 获取每一行的数据
    int id = cursor.getInt(cursor.getColumnIndex("id"));
    String title = cursor.getString(cursor.getColumnIndex("title"));
    String author = cursor.getString(cursor.getColumnIndex("author"));

    // 处理获取的数据,例如打印出来
    System.out.println("ID: " + id + ", Title: " + title + ", Author: " + author);
}

// 关闭 Cursor,释放资源
cursor.close();

// 关闭数据库连接
db.close();

从官方文档中找到这里用到的Cursor方法 

以下是整体的代码

package com.example.sqlite_test;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.List;

public class MyDataHelper extends SQLiteOpenHelper {
    public static final String TABLE_NAME = "book";//表名常量
    public static final String COLUMN_ID = "id";//id列名常量
    public static final String COLUMN_TITLE = "title";//书名列名常量
    public static final String COLUMN_AUTHOR = "author";//作者列名常量

    //构造函数 MyDataHelper 调用父类的构造函数,传入数据库名称 books.db 和版本号 1
    public MyDataHelper(@Nullable Context context) {
//        这是调用 SQLiteOpenHelper 的构造函数,初始化一个 SQLite 数据库帮助类。
//        context: 应用的上下文,用于访问应用的资源和类。
//        "books.db": 数据库的名称。这个数据库文件将在应用的默认数据库路径中创建。如果文件不存在,它将被创建;如果文件已经存在,它将被打开。
//        null: CursorFactory,通常设置为 null。如果提供了一个 CursorFactory,它将用于创建游标对象,通常我们不需要自定义游标,所以传 null。
//        1: 数据库的版本号。数据库的版本号用于管理数据库的升级和降级。当版本号发生变化时,onUpgrade 或 onDowngrade 方法会被调用,以处理数据库的结构变化。
        super(context, "books.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        //创建表的sql语句,创建 book 表。
        //表包含三个列:id(自增主键)、title(文本)和 author(文本)。
        String sql= "CREATE TABLE " + TABLE_NAME + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_TITLE + " TEXT," + COLUMN_AUTHOR + " TEXT)";
        sqLiteDatabase.execSQL(sql);//使用 execSQL 方法执行创建表的 SQL 语句。
    }
    //数据库更新时调用
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        // 该方法用于数据库版本升级时调用,这里没有实现具体的逻辑
    }
    //添加一条书籍记录
    public String addOne(BookModel bookModel)
    {
        ContentValues cv=new ContentValues();
        //使用 ContentValues 对象 cv 存储书籍的 title 和 author
        cv.put(COLUMN_AUTHOR,bookModel.getAuthor());
        cv.put(COLUMN_TITLE,bookModel.getTitle());
        SQLiteDatabase sqLiteDatabase=this.getWritableDatabase();
        //TABLE_NAME: 表示要插入记录的表名,这里是 "book" 表。
        //COLUMN_AUTHOR: 通常用来指定一个列名,当 ContentValues 为空时,该列会被插入空值。我们使用了 ContentValues 来指定要插入的列和值。
        //cv: 一个 ContentValues 对象,包含要插入的列名和对应的值。
        long insert=sqLiteDatabase.insert(TABLE_NAME,null,cv);//使用 insert 方法将 cv 中的数据插入到 book 表中。
        //如果插入成功,insert 变量将返回新插入记录的行ID;如果失败,则返回 -1。
        if(insert==-1)
        {
            return "fail";
        }
        sqLiteDatabase.close();
        return "success";
    }
    //删除一条书籍记录
    public String deleteOne(BookModel bookModel)
    {
        SQLiteDatabase sqLiteDatabase=this.getWritableDatabase();
        //TABLE_NAME: 表示要删除记录的表名,这里是 "book" 表。
        //COLUMN_ID + "=?": WHERE 子句,指定删除条件,这里是 id 列等于某个值。
        //new String[]{String.valueOf(bookModel.getId())}: WHERE 子句中的参数数组,用于替换 ?,这里是书籍的 id。
        int delete=sqLiteDatabase.delete(TABLE_NAME,COLUMN_ID+ "=?",new String[]{String.valueOf(bookModel.getId())});//使用 delete 方法根据书籍的 id 删除相应的记录
        sqLiteDatabase.close();
        //如果删除成功,delete 变量将返回删除的行数;如果失败,则返回0
        if(delete==0)
        {
            return "fail";
        }
        return "success";
    }
    //更新一条书籍记录
    public String updateOne(BookModel bookModel)
    {
        ContentValues cv=new ContentValues();
        cv.put(COLUMN_AUTHOR,bookModel.getAuthor());
        cv.put(COLUMN_TITLE,bookModel.getTitle());
        SQLiteDatabase sqLiteDatabase=this.getWritableDatabase();
//        TABLE_NAME: 表示要更新记录的表名,这里是 "book" 表。
//        cv: 一个 ContentValues 对象,包含要更新的列名和对应的新值。
//        COLUMN_ID + "=?": WHERE 子句,指定更新条件,这里是 id 列等于某个值。
//        new String[]{String.valueOf(bookModel.getId())}: WHERE 子句中的参数数组,用于替换 ?,这里是书籍的 id。
        int update = sqLiteDatabase.update(TABLE_NAME, cv, COLUMN_ID + "=?", new String[]{String.valueOf(bookModel.getId())});//使用 update 方法根据书籍的 id 更新相应的记录。
        //如果更新成功,update 变量将返回更新的行数;如果失败,则返回 0。
        if(update==0)
        {
            return "fail";
        }
        return "success";
    }
    //获取所有书籍列表
    public List<BookModel> getAll()
    {
        List<BookModel> list=new ArrayList<>();//声明了一个 List<BookModel> 类型的列表 list,用于存储从数据库中检索到的书籍记录。

        String sql="SELECT * FROM "+TABLE_NAME;//定义一个 SQL 查询字符串 sql,用于从数据库中的表(TABLE_NAME,即 book 表)中选择所有的记录。

        SQLiteDatabase sqLiteDatabase=this.getReadableDatabase();//调用 getReadableDatabase 方法获取一个可读的 SQLiteDatabase 对象 sqLiteDatabase,用于执行读取操作。

        Cursor cursor= sqLiteDatabase.rawQuery(sql,null);//使用 sqLiteDatabase 对象执行前面定义的 SQL 查询,并返回一个 Cursor 对象 cursor,该对象指向查询结果集。

        //获取每列的索引值(COLUMN_ID、COLUMN_TITLE 和 COLUMN_AUTHOR),这些列对应数据库表中的列(即 id、title 和 author)。
        //通过列名获取该列的索引。如果列名不存在,返回 -1。
        int idIndex=cursor.getColumnIndex(COLUMN_ID);
        int titleIndex=cursor.getColumnIndex(COLUMN_TITLE);
        int authorIndex=cursor.getColumnIndex(COLUMN_AUTHOR);

        //使用 while 循环遍历 Cursor 对象中的每一条记录。moveToNext 方法将 Cursor 移动到下一行,如果有更多行则返回 true,否则返回 false
        //在循环体内,通过 cursor 获取当前记录的 id、title 和 author 的值,并创建一个新的 BookModel 对象 bookModel。
        //将创建的 BookModel 对象添加到 list 中。
        while(cursor.moveToNext())
        {
            BookModel bookModel=new BookModel(cursor.getInt(idIndex),cursor.getString(titleIndex),cursor.getString(authorIndex));
            list.add(bookModel);
        }

        cursor.close();
        sqLiteDatabase.close();
        return list;
    }
}

UpdateActivity

在主页面选择更新数据后跳转到此活动,功能很简单,都是利用之前创建好的函数方法进行数据库中数据的修改。

直接放上完整代码

package com.example.sqlite_test;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class UpdateActivity extends AppCompatActivity {
    TextView update_title,update_author;
    Button update_btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_update);
        //获取从MainActivity传递过来的数据
        Intent intent=getIntent();
        int id = intent.getIntExtra("id",0);
        String title=intent.getStringExtra("title");
        String author=intent.getStringExtra("author");

        update_title=findViewById(R.id.update_title);
        update_author=findViewById(R.id.update_author);
        update_btn=findViewById(R.id.update_btn);
        //传入原始值,书名和作者名
        update_author.setText(author);
        update_title.setText(title);

        update_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //创建新的BookModel对象,用于更新数据库中的数据
                BookModel bookModel=new BookModel(id,update_title.getText().toString(),update_author.getText().toString());
                MyDataHelper myDataHelper=new MyDataHelper(UpdateActivity.this);
                myDataHelper.updateOne(bookModel);//调用MyDataHelper类更新数据
                finish();//结束当前activity,返回上一个界面
                
            }
        });
    }
}

MainActivity

首先是最基础的初始化组件

TextView add_title,add_author;//用于输入书名和作者的文本视图
    Button add_btn;//添加按钮
    ListView view_all;//显示所有书籍的列表视图
    MyDataHelper myDataHelper;//MyDataHelper类实例
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化视图组件
        add_author=findViewById(R.id.add_author);
        add_btn=findViewById(R.id.add_btn);
        add_title=findViewById(R.id.add_title);
        view_all=findViewById(R.id.view_all);

        myDataHelper=new MyDataHelper(MainActivity.this);//初始化MyDataHelper类
        viewAll(myDataHelper);//显示所有书籍列表

然后在这个页面里最重要的操作就是把输入框里的内容添加到数据库中。

BookModel的构造函数用于存储输入的书名和作者名

BookModel bookModel=new BookModel(-1,add_title.getText().toString(),add_author.getText().toString());
// 创建一个新的 MyDataHelper 对象,用于与数据库进行交互。
// MainActivity.this 作为上下文传递给 MyDataHelper。
myDataHelper=new MyDataHelper(MainActivity.this);
// 调用 MyDataHelper 对象的 addOne 方法,将新创建的 BookModel 对象添加到数据库中。
// addOne 方法返回一个字符串,表示操作的结果(例如 "success" 或 "fail")。
String s = myDataHelper.addOne(bookModel);//调用MyDataHelper类,添加数据
Toast.makeText(MainActivity.this,"ADD:"+s,Toast.LENGTH_SHORT).show();
//注意区分函数viewAll和组件view_All
//刷新列表显示最新数据
viewAll(myDataHelper);

提前放上viewAll方法,也就是调用MyDataHelper类中的getAll方法,把数据库中的数据添加到列表中可视化

private void viewAll(MyDataHelper myDataHelper) {
        /* 创建一个适配器,将数据库中的所有书籍数据传递给适配器
           创建一个 ArrayAdapter 对象,适配器用于将数据源(这里是所有书籍信息)与 ListView 进行绑定。
           ArrayAdapter<BookModel> adapter 的作用是将 BookModel 对象列表映射到 ListView 上。
           虽然没有显式调用 toString 方法,但 ArrayAdapter 在内部会调用对象的 toString 方法来获取每个 BookModel 的字符串表示,以便显示在列表项中。
           android.R.layout.simple_list_item_1:系统提供的简单布局文件,用于显示列表项的布局。
           myDataHelper.getAll():调用 MyDataHelper 对象的 getAll 方法,从数据库中获取所有书籍信息,返回一个 List<BookModel>。*/
        ArrayAdapter<BookModel> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, myDataHelper.getAll());
        /* 将适配器设置给 ListView 以便在界面上显示数据
           将创建的适配器设置给 ListView(这里的 view_all)。
           这样,ListView 就能显示适配器中的数据,也就是数据库中所有的书籍信息。*/
        view_all.setAdapter(adapter);
    }

其中ArrayAdapter又是一个新的类,这里简单进行介绍。

ArrayAdapter是 Android 提供的一个适配器类,用于将数据源(如数组或 List)与 ListView 视图进行绑定。它将数据转换为视图项,从而可以在这些视图中显示数据。

最后是给ListView中的每一条数据添加点击事件:增加一个弹窗,在弹窗中选择对于此条数据进行修改或者删除。

view_all.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            //parent(即 ListView),view(被点击的项),position(项的位置)和 id(项的 ID)
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //知道他点击的位置,即获取点击的书籍对象
                BookModel bookModel=(BookModel) parent.getItemAtPosition(position);
                //弹出对话框,提示用户选择操作
                AlertDialog.Builder dialog=new AlertDialog.Builder(MainActivity.this);
                dialog.setTitle("请选择操作");

选择删除,则新建MyDataHelper对象以调取之前已经创建好的删除方法,然后调用viewAll更新列表.

 //设置“删除”按钮的点击事件
dialog.setNegativeButton("删除", new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
     // 调用删除方法删除选中的书籍
     String s= myDataHelper.deleteOne(bookModel);              
     Toast.makeText(MainActivity.this,"DELETE:"+s,Toast.LENGTH_SHORT).show();
     // 刷新列表显示最新数据
     viewAll(myDataHelper);//刷新列表显示最新数据
                    }
                });

选择修改,则带着现有的数据跳转到UpdataActivity页面,在UpdataActivity中进行替换 。

dialog.setPositiveButton("修改", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    //跳转到UpdateActivity并且传递数据
       Intent intent=new Intent(MainActivity.this,UpdateActivity.class);
       intent.putExtra("id",bookModel.getId());
       intent.putExtra("title",bookModel.getTitle());
       intent.putExtra("author",bookModel.getAuthor());
       startActivity(intent);
                    }
                });

刚才提到了一个新的功能,弹出的对话框AlertDialog。我自认为在这位大佬的博客上讲解得很清楚很全面,放上链接https://blog.csdn.net/u014316335/article/details/137926342

以下是完整代码

package com.example.sqlite_test;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.w3c.dom.Text;

public class MainActivity extends AppCompatActivity{
    TextView add_title,add_author;//用于输入书名和作者的文本视图
    Button add_btn;//添加按钮
    ListView view_all;//显示所有书籍的列表视图
    MyDataHelper myDataHelper;//MyDataHelper类实例

    //每次打开都刷新listview
    @Override
    protected void onRestart() {
        super.onRestart();
        viewAll(myDataHelper);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化视图组件
        add_author=findViewById(R.id.add_author);
        add_btn=findViewById(R.id.add_btn);
        add_title=findViewById(R.id.add_title);
        view_all=findViewById(R.id.view_all);

        myDataHelper=new MyDataHelper(MainActivity.this);//初始化MyDataHelper类
        viewAll(myDataHelper);//显示所有书籍列表

        //设置添加按钮的点击监听器
        add_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建一个新的 BookModel 对象,-1 表示这是一个新的书籍,尚未在数据库中分配 ID。
                // 从用户输入的 TextView 中获取书名和作者名,并设置到 BookModel 对象中。
                BookModel bookModel=new BookModel(-1,add_title.getText().toString(),add_author.getText().toString());
                // 创建一个新的 MyDataHelper 对象,用于与数据库进行交互。
                // MainActivity.this 作为上下文传递给 MyDataHelper。
                myDataHelper=new MyDataHelper(MainActivity.this);
                // 调用 MyDataHelper 对象的 addOne 方法,将新创建的 BookModel 对象添加到数据库中。
                // addOne 方法返回一个字符串,表示操作的结果(例如 "success" 或 "fail")。
                String s = myDataHelper.addOne(bookModel);//调用MyDataHelper类,添加数据
                Toast.makeText(MainActivity.this,"ADD:"+s,Toast.LENGTH_SHORT).show();
                //注意区分函数viewAll和组件view_All
                //刷新列表显示最新数据
                viewAll(myDataHelper);
            }
        });
        //list组件的点击监听器与其他监听器不同
        view_all.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            //parent(即 ListView),view(被点击的项),position(项的位置)和 id(项的 ID)
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //知道他点击的位置,即获取点击的书籍对象
                BookModel bookModel=(BookModel) parent.getItemAtPosition(position);
                //弹出对话框,提示用户选择操作
                AlertDialog.Builder dialog=new AlertDialog.Builder(MainActivity.this);
                dialog.setTitle("请选择操作");
                //设置“删除”按钮的点击事件
                dialog.setNegativeButton("删除", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 调用删除方法删除选中的书籍
                        String s= myDataHelper.deleteOne(bookModel);
                        Toast.makeText(MainActivity.this,"DELETE:"+s,Toast.LENGTH_SHORT).show();
                        // 刷新列表显示最新数据
                        viewAll(myDataHelper);//刷新列表显示最新数据
                    }
                });
                // 设置“修改”按钮的点击事件
                dialog.setPositiveButton("修改", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //跳转到UpdateActivity并且传递数据
                        Intent intent=new Intent(MainActivity.this,UpdateActivity.class);
                        intent.putExtra("id",bookModel.getId());
                        intent.putExtra("title",bookModel.getTitle());
                        intent.putExtra("author",bookModel.getAuthor());
                        startActivity(intent);

                    }
                });
                dialog.create();
                dialog.show();
            }
        });
    }
    //显示所有书籍列表的方法
    private void viewAll(MyDataHelper myDataHelper) {
        /* 创建一个适配器,将数据库中的所有书籍数据传递给适配器
           创建一个 ArrayAdapter 对象,适配器用于将数据源(这里是所有书籍信息)与 ListView 进行绑定。
           ArrayAdapter<BookModel> adapter 的作用是将 BookModel 对象列表映射到 ListView 上。
           虽然没有显式调用 toString 方法,但 ArrayAdapter 在内部会调用对象的 toString 方法来获取每个 BookModel 的字符串表示,以便显示在列表项中。
           android.R.layout.simple_list_item_1:系统提供的简单布局文件,用于显示列表项的布局。
           myDataHelper.getAll():调用 MyDataHelper 对象的 getAll 方法,从数据库中获取所有书籍信息,返回一个 List<BookModel>。*/
        ArrayAdapter<BookModel> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, myDataHelper.getAll());
        /* 将适配器设置给 ListView 以便在界面上显示数据
           将创建的适配器设置给 ListView(这里的 view_all)。
           这样,ListView 就能显示适配器中的数据,也就是数据库中所有的书籍信息。*/
        view_all.setAdapter(adapter);
    }

}

END

安卓开发自学笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值