48. 【Android教程】数据库:SQLite 的使用

简介: 48. 【Android教程】数据库:SQLite 的使用

今天来学习另一种比较专业的存储方式——数据库,在 Android 中引入了一个轻量级的数据库框架:SQLite。如果你对数据库非常熟悉,那它可以全面支持数据的 SQL 语言,同时也提供了 Java 接口方便不太熟悉数据库的 Android 工程师使用。

1. SQLite 是什么

SQLite 是一个开源的轻量级关系数据库管理系统,简称RDMS(Relational Database Management System)。Android 通过 SQLIte 来进行数据库增删改查等相关操作,如果想进一步了解 SQLite,可以参考网上教程的数据库相关课程,这里主要围绕 Android 中的使用方法来展开。

Android 已经预置了 SQLite DateBase,所以我们不需要做任何的依赖配置,跟前面几种存储方式一样,存储在 SQLite 的数据也是 App 的私有数据,也就是只有自己的 App 能够访问,这样能够保证数据安全。

2. 数据库辅助类

为了帮助我们快速使用数据库,Android 系统封装了一个辅助类——SQLite Helper,可以通过辅助类完成数据库的更新、升级等操作,SQLite Helper 使用示例如下:

public class DbHandler extends SQLiteOpenHelper {
    private static final int DB_VERSION = 1;
    private static final String DB_NAME = "usersdb";
    private static final String TABLE_Users = "userdetails";
    private static final String KEY_ID = "id";
    private static final String KEY_NAME = "name";
    private static final String KEY_LOC = "location";
    private static final String KEY_DESG = "designation";
    public DbHandler(Context context){
        super(context,DB_NAME, null, DB_VERSION);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
       // 创建表格
        String CREATE_TABLE = "CREATE TABLE " + TABLE_Users + "("
                + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + KEY_NAME + " TEXT,"
                + KEY_LOC + " TEXT,"
                + KEY_DESG + " TEXT"+ ")";
        db.execSQL(CREATE_TABLE);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 删除表格
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_Users);
        // 重建
        onCreate(db);
    }
}

在代码中我们创建了一个名叫“ usersdb”的数据库,在“ usersdb”中创建了一张名为“ userdetails”的表格,里面包含姓名、地址位置、描述等用户信息。细心的读者可能会注意到,代码中存在两个生命周期回调方法:


onCreate(SQLiteDatabase db):

当数据库被创建的时候回调,此方法在整个 App 运行期间只会被回调一次,在数据库创建好之后就不会再回调,通常会把数据库中的表格创建代码写在onCreate()中。


onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):

当数据库需要升级时调用,通常发生在 App 覆盖升级的时候。当我们需要修改数据库,比如删除字段、增加表格、修改字段等等操作的时候,需要将对应数据库的版本号 +1,此时在 App 升级之后发现版本号有变化,便会回调此方法,我们可以在onUpgrade()方法中做数据的适配及搬迁。

3. 使用 SQL 操作数据库

前面提到过,我们完全可以通过传统的 SQL 语言来操作数据库。

3.1 SQL 语言执行方法

Android 为我们提供了以下方法来执行 SQL:

  • **execSQL(SQL,Object[]):**执行带占位符的SQL语句,用于修改数据库内容
  • **rawQuery(SQL,Object[]):**执行带占位符的SQL查询语句,返回查询结构的游标指针——Cursor

3.2 数据库查询指针

Cursor 相当于一个数据库指针,指向查询的结果,我们可以通过移动 Cursor 来获取想要的数据,Cursor支持以下方法:

  • move(offset):
  • 向上或者向下移动,参数是移动的行数,正数表示向下,负数向上
  • moveToFirst():
  • 移动到第一行,移动成功返回 true,否则为 false
  • moveToLast():
  • 移动到最后一行,成功返回true,否则为 flase
  • moveToNext():
  • 移动到下一行,成功返回true,否则为 false
  • moveToPrevious():
  • 移动到前一条数据
  • getCount():
  • 获得总得数据条数
  • isFirst():
  • 判断当前是否是第一条记录
  • isLast():
  • 判断是否是最后一条记录
  • moveToPosition(int):
  • 直接移动到指定行

4. 使用 Android 接口操作数据库

如果你对数据库并不是很熟悉或者不想用 SQL 来操作数据库,同样可以采用纯 Java 接口来操作。在 Android 中数据库的内容用 ContentValues 表示,所以我们的增删改查其实都是对某个 ContentValues 进行操作。

4.1 插入数据

我们通过insert()方法进行插入:

// 采用写模式获取数据库对象
SQLiteDatabase db = this.getWritableDatabase();
// 创建一个数据表,key 就是表格每一列的列名
ContentValues cValues = new ContentValues();
cValues.put(KEY_NAME, name);
cValues.put(KEY_LOC, location);
cValues.put(KEY_DESG, designation);
// 添加一行数据,返回这一行的主 key
long newRowId = db.insert(TABLE_Users,null, cValues);

4.2 查询数据

查询数据是通过query()方法实现的:

// 以写模式获取数据库对象
SQLiteDatabase db = this.getWritableDatabase();
// 从TABLE_Users中查询指定userid的数据的名称、位置、描述信息
Cursor cursor = db.query(TABLE_Users, new String[]{KEY_NAME, KEY_LOC, KEY_DESG}, KEY_ID+ "=?",new String[]{String.valueOf(userid)},null, null, null, null);

4.3 更新数据

更新数据使用update()方法:

// 以写的模式获取数据库对象
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cVals = new ContentValues();
cVals.put(KEY_LOC, location);
cVals.put(KEY_DESG, designation);
int count = db.update(TABLE_Users, cVals, KEY_ID+" = ?",new String[]{String.valueOf(id)});

4.4 删除数据

删除数据使用delete()方法

SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_Users, KEY_ID+" = ?",new String[]{String.valueOf(userid)});

以上就是 SQLite 的 CURD(insert、update、delete、query)操作对应的几个系统 API。

5. SQLite 使用示例

数据库通常用于存储批量的 Key-Value,比如通讯录里、短信、用户信息等。本节就借用上一节的例子,在 SharePreferenced 一节中我们实现了一个登陆框,这一节我们稍作修改,做一个用户信息登记表。首页类似登录框一样提供一个用户信息等级的页面,然后登记完我们通过 ListView 展示所有用户信息。为了方便大家理解,我们来统计一下王者荣耀英雄的名称、主打位置以及特征描述。



5.1 英雄登记页面

等级页面主要两部分组成:

  • **信息输入框:**包含名称、主打位置、特征
  • 确认登记 Button
<?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">
 
    <TextView
        android:id="@+id/fstTxt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:layout_marginTop="150dp"
        android:text="名称" />
 
    <EditText
        android:id="@+id/txtName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:ems="10" />
 
    <TextView
        android:id="@+id/secTxt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:text="主打位置" />
 
    <EditText
        android:id="@+id/txtLocation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:ems="10" />
 
    <TextView
        android:id="@+id/thirdTxt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:text="特征描述" />
 
    <EditText
        android:id="@+id/txtDesignation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="100dp"
        android:ems="10" />
 
    <Button
        android:id="@+id/btnSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:text="确认登记" />
</LinearLayout>

5.2 数据库辅助类

辅助类就是提供操作英雄登记表数据的增删改查,使用第 4 小节学习的 API 即可,创建“DbHelper.Java”类,编写如下代码:

package com.emercy.myapplication;
 
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
 
import java.util.ArrayList;
import java.util.HashMap;
 
public class DbHelper extends SQLiteOpenHelper {
    private static final int DB_VERSION = 1;
    private static final String DB_NAME = "herodb";
    private static final String TABLE_Heres = "herodetails";
    private static final String KEY_ID = "id";
    static final String KEY_NAME = "name";
    static final String KEY_POS = "position";
    static final String KEY_DESG = "designation";
 
    public DbHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }
 
    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_TABLE = "CREATE TABLE " + TABLE_Heres + "("
                + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + KEY_NAME + " TEXT,"
                + KEY_POS + " TEXT,"
                + KEY_DESG + " TEXT" + ")";
        db.execSQL(CREATE_TABLE);
 
        initHero(db, "安琪拉","中路", "草丛");
        initHero(db, "马超","对抗路", "帅气");
        initHero(db, "伽罗","发育路", "禁掉");
        initHero(db, "鲁班","发育路", "手长");
        initHero(db, "兰陵王","打野", "绕后");
        initHero(db, "猴子","打野", "爆发");
    }
 
    private void initHero(SQLiteDatabase db, String name, String location, String designation) {
        ContentValues cValues = new ContentValues();
        cValues.put(KEY_NAME, name);
        cValues.put(KEY_POS, location);
        cValues.put(KEY_DESG, designation);
        long newRowId = db.insert(TABLE_Heres, null, cValues);
    }
 
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 重建数据表
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_Heres);
        onCreate(db);
    }
 
    // 增加英雄角色详情
    void insertUserDetails(String name, String location, String designation) {
        // 获取可写数据库对象
        SQLiteDatabase db = this.getWritableDatabase();
        // 以key为列创建数据
        ContentValues cValues = new ContentValues();
        cValues.put(KEY_NAME, name);
        cValues.put(KEY_POS, location);
        cValues.put(KEY_DESG, designation);
 
        long newRowId = db.insert(TABLE_Heres, null, cValues);
        db.close();
    }
 
    // 查询数据详情
    public ArrayList<HashMap<String, String>> GetUsers() {
        SQLiteDatabase db = this.getWritableDatabase();
        ArrayList<HashMap<String, String>> userList = new ArrayList<>();
        StringBuilder queryBuilder = new StringBuilder();
        String query = "SELECT " + KEY_NAME + ", " + KEY_POS + ", " + KEY_DESG + " FROM " + TABLE_Heres;
        Cursor cursor = db.rawQuery(query, null);
        while (cursor.moveToNext()) {
            HashMap<String, String> user = new HashMap<>();
            user.put(KEY_NAME, cursor.getString(cursor.getColumnIndex(KEY_NAME)));
            user.put(KEY_POS, cursor.getString(cursor.getColumnIndex(KEY_POS)));
            user.put(KEY_DESG, cursor.getString(cursor.getColumnIndex(KEY_DESG)));
            userList.add(user);
        }
        return userList;
    }
 
    // 获取某个英雄的详情数据
    public ArrayList<HashMap<String, String>> GetUserByUserId(int userid) {
        SQLiteDatabase db = this.getWritableDatabase();
        ArrayList<HashMap<String, String>> userList = new ArrayList<>();
        String query = "SELECT name, location, designation FROM " + TABLE_Heres;
        Cursor cursor = db.query(TABLE_Heres, new String[]{KEY_NAME, KEY_POS, KEY_DESG}, KEY_ID + "=?", new String[]{String.valueOf(userid)}, null, null, null, null);
        if (cursor.moveToNext()) {
            HashMap<String, String> user = new HashMap<>();
            user.put("name", cursor.getString(cursor.getColumnIndex(KEY_NAME)));
            user.put("designation", cursor.getString(cursor.getColumnIndex(KEY_DESG)));
            user.put("location", cursor.getString(cursor.getColumnIndex(KEY_POS)));
            userList.add(user);
        }
        return userList;
    }
 
    // 删除数据
    public void DeleteUser(int userid) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(TABLE_Heres, KEY_ID + " = ?", new String[]{String.valueOf(userid)});
        db.close();
    }
 
    // 更新英雄数据
    public int UpdateUserDetails(String location, String designation, int id) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues cVals = new ContentValues();
        cVals.put(KEY_POS, location);
        cVals.put(KEY_DESG, designation);
        int count = db.update(TABLE_Heres, cVals, KEY_ID + " = ?", new String[]{String.valueOf(id)});
        return count;
    }
}

我们在onCreate中创建了英雄表格,并预置了几条英雄数据(英雄描述纯手打,有误请谅解 - -!),接着对外暴露了表格的 CURD 接口。

5.3 英雄登记逻辑

读取输入框的英雄属性,接着通过DbHelper类提供的 API 进行插入操作:

 
package com.emercy.myapplication;
 
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
 
public class MainActivity extends Activity {
    EditText name, loc, desig;
    Button saveBtn;
    Intent intent;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        name = (EditText) findViewById(R.id.txtName);
        loc = (EditText) findViewById(R.id.txtLocation);
        desig = (EditText) findViewById(R.id.txtDesignation);
        saveBtn = (Button) findViewById(R.id.btnSave);
        saveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String username = name.getText().toString();
                String location = loc.getText().toString();
                String designation = desig.getText().toString();
                DbHelper DbHelper = new DbHelper(MainActivity.this);
                DbHelper.insertUserDetails(username, location, designation);
                intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
                Toast.makeText(getApplicationContext(), "英雄信息登记成功", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

5.4 英雄列表 listView

创建 list.xml 布局文件,用来展示英雄的名称、位置和描述:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="5dp">
 
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="17sp"
        android:textStyle="bold" />
 
    <TextView
        android:id="@+id/designation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/name"
        android:layout_marginTop="7dp"
        android:textColor="#343434"
        android:textSize="14dp" />
 
    <TextView
        android:id="@+id/location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/designation"
        android:layout_alignBottom="@+id/designation"
        android:layout_alignParentEnd="true"
        android:textColor="#343434"
        android:textSize="14sp" />
</RelativeLayout>

5.5 英雄列表展示

最后就是一个英雄列表的 Activity,里面放置一个 listView用于展示所有的英雄数据:

package com.emercy.myapplication;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
 
import java.util.ArrayList;
import java.util.HashMap;
 
import static com.emercy.myapplication.DbHelper.KEY_DESG;
import static com.emercy.myapplication.DbHelper.KEY_NAME;
import static com.emercy.myapplication.DbHelper.KEY_POS;
 
public class SecondActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second);
        DbHelper db = new DbHelper(this);
        ArrayList<HashMap<String, String>> userList = db.GetUsers();
        ListView lv = (ListView) findViewById(R.id.user_list);
        ListAdapter adapter = new SimpleAdapter(SecondActivity.this, userList, R.layout.list, new String[]{KEY_NAME, KEY_DESG, KEY_POS}, new int[]{R.id.name, R.id.designation, R.id.location});
        lv.setAdapter(adapter);
        Button back = (Button) findViewById(R.id.btnBack);
        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

通过DbHelper提供的检索接口,拿到每一行的数据绑定到 ListView 上即可。编译运行,完成登陆之后便会跳转到英雄列表,此时列表中展示的是预置的数据以及我们刚刚登记的数据。


最后记得在 AndroidManifest.xml 中添加 SecondActivity 的注册。


 

        <activity android:name=".SecondActivity" />

6. 小结

本节学习了一个比较专业的存储方式,SQLite 是一种轻量级的开源数据库框架,已经被预置到 Android 系统中,我们可以非常方便的使用。既可以通过标准的 SQL 语句进行操作,也可以使用Android 提供的 Java 接口做 CURD。通过最后一个例子可以学习到 SQLite 的所有常用接口,在今后需要用到数据库的时候,可以回头来看看本节的例子。

相关文章
|
9天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
22天前
|
存储 SQL 数据库
数据库知识:了解SQLite或其他移动端数据库的使用
【10月更文挑战第22天】本文介绍了SQLite在移动应用开发中的应用,包括其优势、如何在Android中集成SQLite、基本的数据库操作(增删改查)、并发访问和事务处理等。通过示例代码,帮助开发者更好地理解和使用SQLite。此外,还提到了其他移动端数据库的选择。
25 8
|
1月前
|
Web App开发 SQL 数据库
使用 Python 解析火狐浏览器的 SQLite3 数据库
本文介绍如何使用 Python 解析火狐浏览器的 SQLite3 数据库,包括书签、历史记录和下载记录等。通过安装 Python 和 SQLite3,定位火狐数据库文件路径,编写 Python 脚本连接数据库并执行 SQL 查询,最终输出最近访问的网站历史记录。
|
30天前
|
存储 SQL 关系型数据库
【入门级教程】MySQL:从零开始的数据库之旅
本教程面向零基础用户,采用通俗易懂的语言和丰富的示例,帮助你快速掌握MySQL的基础知识和操作技巧。内容涵盖SQL语言基础(SELECT、INSERT、UPDATE、DELETE等常用语句)、使用索引提高查询效率、存储过程等。适合学生、开发者及数据库爱好者。
40 0
【入门级教程】MySQL:从零开始的数据库之旅
|
1月前
|
tengine 关系型数据库 MySQL
Tengine、Nginx安装MySQL数据库命令教程
本指南详细介绍了在Linux系统上安装与配置MySQL数据库的步骤。首先通过下载并安装MySQL社区版本,接着启动MySQL服务,使用`systemctl start mysqld.service`命令。若启动失败,可尝试使用`sudo /etc/init.d/mysqld start`。利用`systemctl status mysqld.service`检查MySQL的服务状态,确保其处于运行中。通过日志文件获取初始密码,使用该密码登录数据库,并按要求更改初始密码以增强安全性。随后创建一个名为`tengine`的数据库,最后验证数据库创建是否成功以及完成整个设置流程。
|
2月前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
|
1月前
|
存储 关系型数据库 数据库
轻量级数据库的利器:Python 及其内置 SQLite 简介
轻量级数据库的利器:Python 及其内置 SQLite 简介
|
1月前
|
应用服务中间件 PHP Apache
PbootCMS提示错误信息“未检测到您服务器环境的sqlite3数据库扩展...”
PbootCMS提示错误信息“未检测到您服务器环境的sqlite3数据库扩展...”
|
2月前
|
存储 API 数据库
QML使用Sqlite数据库存储ListModel数据
本文介绍了在QML中使用Sqlite数据库存储ListModel数据的方法,包括如何创建数据库、读取数据、动态添加和删除数据,以及如何在程序启动和退出时与数据库同步数据。
|
1月前
|
SQL NoSQL MongoDB
一款基于分布式文件存储的数据库MongoDB的介绍及基本使用教程
一款基于分布式文件存储的数据库MongoDB的介绍及基本使用教程
41 0