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 的所有常用接口,在今后需要用到数据库的时候,可以回头来看看本节的例子。

相关文章
|
1月前
|
SQL 数据库连接 数据库
在C++的QT框架中实现SQLite数据库的连接与操作
以上就是在C++的QT框架中实现SQLite数据库的连接与操作的基本步骤。这些步骤包括创建数据库连接、执行SQL命令、处理查询结果和关闭数据库连接。在实际使用中,你可能需要根据具体的需求来修改这些代码。
146 14
|
3月前
|
存储 关系型数据库 分布式数据库
PolarDB 开源基础教程系列 8 数据库生态
PolarDB是一款开源的云原生分布式数据库,源自阿里云商业产品。为降低使用门槛,PolarDB携手伙伴打造了完整的开源生态,涵盖操作系统、芯片、存储、集成管控、监控、审计、开发者工具、数据同步、超融合计算、ISV软件、开源插件、人才培养、社区合作及大型用户合作等领域。通过这些合作伙伴,PolarDB提供了丰富的功能和服务,支持多种硬件和软件环境,满足不同用户的需求。更多信息请访问[PolarDB开源官方网站](https://openpolardb.com/home)。
145 4
|
4月前
|
关系型数据库 MySQL API
新手教程:数据库操作(使用PDO或MySQLi扩展)
本文为新手介绍如何使用PDO和MySQLi扩展连接与操作MySQL数据库。PDO更现代灵活,支持多种数据库,适合大多数应用;MySQLi提供面向过程和面向对象两种API,适合直接控制数据库操作。教程涵盖安装配置、创建连接、执行查询(查询、插入、更新、删除)及错误处理等内容。希望这篇教程能帮助你快速上手PHP中的数据库操作!
234 32
|
5月前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
645 15
|
6月前
|
Android开发 数据安全/隐私保护 虚拟化
安卓手机远程连接登录Windows服务器教程
安卓手机远程连接登录Windows服务器教程
1071 4
|
6月前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
6月前
|
存储 SQL 数据库
数据库知识:了解SQLite或其他移动端数据库的使用
【10月更文挑战第22天】本文介绍了SQLite在移动应用开发中的应用,包括其优势、如何在Android中集成SQLite、基本的数据库操作(增删改查)、并发访问和事务处理等。通过示例代码,帮助开发者更好地理解和使用SQLite。此外,还提到了其他移动端数据库的选择。
126 8
|
6月前
|
存储 机器学习/深度学习 监控
南大通用GBase 8s数据库onbar基础使用教程
数据备份与恢复是确保数据安全和业务连续性的关键。onbar作为GBase 8s数据库的备份工具,需配合存储管理器使用,通过配置BAR_BSALIB_PATH等参数,实现数据的备份与恢复。本文详细介绍了onbar的配置、备份、恢复及监控流程,帮助数据库管理员构建高效的数据保护方案。
|
7月前
|
Web App开发 SQL 数据库
使用 Python 解析火狐浏览器的 SQLite3 数据库
本文介绍如何使用 Python 解析火狐浏览器的 SQLite3 数据库,包括书签、历史记录和下载记录等。通过安装 Python 和 SQLite3,定位火狐数据库文件路径,编写 Python 脚本连接数据库并执行 SQL 查询,最终输出最近访问的网站历史记录。
114 4
|
7月前
|
存储 SQL 关系型数据库
【入门级教程】MySQL:从零开始的数据库之旅
本教程面向零基础用户,采用通俗易懂的语言和丰富的示例,帮助你快速掌握MySQL的基础知识和操作技巧。内容涵盖SQL语言基础(SELECT、INSERT、UPDATE、DELETE等常用语句)、使用索引提高查询效率、存储过程等。适合学生、开发者及数据库爱好者。
199 0
【入门级教程】MySQL:从零开始的数据库之旅

热门文章

最新文章

推荐镜像

更多