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

相关文章
|
3月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
567 5
|
3月前
|
存储 数据库 开发者
Python SQLite模块:轻量级数据库的实战指南
本文深入讲解Python内置sqlite3模块的实战应用,涵盖数据库连接、CRUD操作、事务管理、性能优化及高级特性,结合完整案例,助你快速掌握SQLite在小型项目中的高效使用,是Python开发者必备的轻量级数据库指南。
293 0
|
7月前
|
XML 数据库 Android开发
Android数据库的使用(增删改查)
本文介绍了一个简单的数据库操作Demo,包含创建数据库、增删改查功能。通过5个按钮分别实现创建数据库、插入数据、删除数据、更新数据和查询数据的操作。代码结构清晰,适合初学者学习Android SQLite数据库基础操作。
218 5
|
7月前
|
数据库 Android开发
Android外部数据库的引用
简介:本文介绍了在Android项目中引用外部数据库的方法。首先,将现成的数据库文件放入项目的`assets`文件夹中(需手动创建)。其次,在APP引导界面通过代码将数据库拷贝至App目录下,确保数据库可用。最后,对数据库进行增删改查等操作。关键步骤包括判断数据库是否存在、使用`AssetManager`读取数据库文件并写入App私有目录,实现外部数据库的顺利集成与使用。
|
7月前
|
数据库 Android开发 开发者
Android常用的room增删改查语句(外部数据库)
本文分享了将一个原生数据库驱动的单词APP重构为使用Room库的过程及遇到的问题,重点解决了Room中增删改查的常用语句实现。文章通过具体示例(以“forget”表为例),详细展示了如何定义实体类、Dao接口、Database类以及Repository和ViewModel的设计与实现。同时,提供了插入、删除、更新和查询数据的代码示例,包括模糊查询、分页加载等功能。此外,针对外部数据库导入问题,作者建议可通过公众号“计蒙不吃鱼”获取更多支持。此内容适合有一定Room基础的开发者深入学习。
235 0
Android常用的room增删改查语句(外部数据库)
|
8月前
|
SQL 数据库连接 数据库
在C++的QT框架中实现SQLite数据库的连接与操作
以上就是在C++的QT框架中实现SQLite数据库的连接与操作的基本步骤。这些步骤包括创建数据库连接、执行SQL命令、处理查询结果和关闭数据库连接。在实际使用中,你可能需要根据具体的需求来修改这些代码。
487 14
|
11月前
|
关系型数据库 MySQL API
新手教程:数据库操作(使用PDO或MySQLi扩展)
本文为新手介绍如何使用PDO和MySQLi扩展连接与操作MySQL数据库。PDO更现代灵活,支持多种数据库,适合大多数应用;MySQLi提供面向过程和面向对象两种API,适合直接控制数据库操作。教程涵盖安装配置、创建连接、执行查询(查询、插入、更新、删除)及错误处理等内容。希望这篇教程能帮助你快速上手PHP中的数据库操作!
341 32
|
10月前
|
存储 关系型数据库 分布式数据库
PolarDB 开源基础教程系列 8 数据库生态
PolarDB是一款开源的云原生分布式数据库,源自阿里云商业产品。为降低使用门槛,PolarDB携手伙伴打造了完整的开源生态,涵盖操作系统、芯片、存储、集成管控、监控、审计、开发者工具、数据同步、超融合计算、ISV软件、开源插件、人才培养、社区合作及大型用户合作等领域。通过这些合作伙伴,PolarDB提供了丰富的功能和服务,支持多种硬件和软件环境,满足不同用户的需求。更多信息请访问[PolarDB开源官方网站](https://openpolardb.com/home)。
495 4
|
12月前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
1113 15
|
存储 SQL 数据库
数据库知识:了解SQLite或其他移动端数据库的使用
【10月更文挑战第22天】本文介绍了SQLite在移动应用开发中的应用,包括其优势、如何在Android中集成SQLite、基本的数据库操作(增删改查)、并发访问和事务处理等。通过示例代码,帮助开发者更好地理解和使用SQLite。此外,还提到了其他移动端数据库的选择。
310 8