Android:数据持久化(2/2) SQLite

Abstract 概述

之前的随笔记录了普通文本文件和SharedPreferences两种保存数据的方式,现在来谈一谈用SQLite这个Android自带的数据库。

对SQLite的操作,从整体上来说分两步:

  1. 自定义一个Helper类,继承自***SQLiteOpenHelper***,用于获取数据库的实例对象(或者说用于打开数据库的助手类);
  2. 通过该Helper类的对象,获取具体的数据库对象来进行CRUD操作;

Description 具体内容

1. 自定义Helper类

借助该Helper类的对象,我们才能获取数据库对象进行操作。
自定义Helper类的要求:

  • 继承SQLiteOpenHelper类;
  • 覆写(Override)onCreate()onUpgrade()两个方法;
public class MyDBHelper extends SQLiteOpenHelper {

    public static final String BOOK_STORE = "BookStore.db";
    public static final String BOOK_TABLE = "Book";

    private Context context;

    public static final String CREATE_BOOK = "create table Book (id integer primary key autoincrement, name text, author text, price real, cover text)";

    public MyDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        this.context = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        Toast.makeText(context, "Database created.", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Toast.makeText(context, "Just upgraded.", Toast.LENGTH_SHORT);
    }
}

说明:

  • 继承了SQLiteOpenHelper;
  • 覆写了onCreate(),该方法在helper第一次获取数据库对象时调用,即创建Book表;
  • 覆写了构造器(构造方法/Constructor),取得调用该实例的context,以便内部使用(如这里的Toast.makeText()需要该参数);

注意:文中用到的文件都是使用Android Studio的默认定义,如MainActivity.java, activity_main.xml等。


2. 获取数据库对象

2. 0 通过adb工具查看数据库内容

在SKD下有一个platform-tools文件夹,里面有一个adb的工具可查看sqlite的数据。 该部分为可选内容,不使用该工具也可以进行开发,只是查看资料会相当不便,所以还是建议学会使用。

  1. 配置环境变量,将platform-tools 目录加入到PATH中;
  2. 运行App,在启动模拟器后,可以在cmd/terminal中输入adb shell启动adb(可通过exit来退出);
  3. 切换目录到数据库所在文件夹:cd /data/data/com.scv.lawrence.databasetesting/databases(此处以Nexus为例,在真机上测试如小米等,目录很有可能不一样);
  4. 通过ls命令可以看到当前所有数据库(参考下面2.1的内容),此时使用sqlite3 databaseName命令可以打开该数据库。如2.1中创建了一个名为BookStore.db的数据库,含有一个Book表,则在adb shell中使用ls时能看到BookStore.dbsqlite3 BookStore.db
  5. 在进入了sqlite3的环境后,可使用.schema来查看创建表所执行的SQL语句,可使用.table来查看所有表的名称,可使用.exit来返回adb shell,同样可使用各种sqlite支持的SQL语句;
2. 1 创建数据库

在布局文件中定义一个按钮。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create DB"
        android:id="@+id/create_db"/>
<LinearLayout/>

在代码中(MainActivity.java)中对按钮的点击事件进行监听绑定,通过定义数据库的名称及版本号来创建Helper类的实例,并通过getWritable()获取该数据库的实例。

Button createDB = (Button) findViewById(R.id.create_db);
createDB.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteOpenHelper helper = new MyDBHelper(MainActivity.this, MyDBHelper.BOOK_STORE, null, 1);//首先要获取相应数据库的helper,才能进行下一步操作
        SQLiteDatabase db = helper.getWritableDatabase();//第一次执行这个方法,会自动调用helper中定义的onCreate()
    }
});

第一次点击创建数据库的按钮,onCreate()中的Toast.makeText()会提示消息表示执行了该方法,第二次点击开始不再有提示,不再执行onCreate();

2. 2 更新数据库

在获取Helper对象时必须传入数据库的名称和版本号,如果传入的版本号高于以前的版本号,则会自动执行onUpgrade()

SQLiteOpenHelper helper = new MyDBHelper(MainActivity.this, MyDBHelper.BOOK_STORE, null, 2);
upgradeDB = (Button) findViewById(R.id.upgrade_db);
upgradeDB.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = helper.getWritableDatabase();//由于helper中的第4个参数,版本信息version高于之前,故调用onUpgrade()
    }
});

3. CRUD操作

CRUD即增(Create)删(Delete)改(Update)查(Retrieve),均可使用执行SQL或调用api两种版本来执行;

3. 1 Create 插入数据
  • 将要插入的数据放入ContentValues的对象中;
  • 调用SQLiteDatabase对象的insert();

定义了两个EditText来输入书名和作者,点击按钮进行插入。(activity_main.xml)

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="book name"
    android:id="@+id/name"/>

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="author"
    android:id="@+id/author"/>

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="create"
    android:id="@+id/create"/>

MainActivity.java

Button createBtn = (Button) findViewById(R.id.create);
createBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String bName = nameEdit.getText().toString();
        String author = authorEdit.getText().toString();

		ContentValues values = new ContentValues();
        values.put("name", bName);
        values.put("author", author);

        SQLiteDatabase db = helper.getWritableDatabase();
        db.insert(MyDBHelper.BOOK_TABLE, null, values);//与下面的SQL语句等价,且为了避免SQL注入攻击,必须使用传参的形式,不能自行拼装SQL语句。
        //db.execSQL("INSERT INTO Book (name, author) VALUES (?, ?)", new Object[]{bName, author});

        values.clear();//清空ContentValues对象的内容,为下次修改作准备
        Toast.makeText(MainActivity.this, "Data inserted.", Toast.LENGTH_SHORT).show();
        nameEdit.setText(null);
        authorEdit.setText(null);
    }
});
3. 2 Update 更新数据
  • 和insert()一样,以ContentValues对象来保存要更新的内容;
  • update()比insert()多了WHERE条件及相应参数;

在布局文件(activity_main.xml)中加入按钮进行update()的绑定:

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="update"
    android:id="@+id/update"/>

MainActivity.java

Button updateBtn = (Button) findViewById(R.id.update);
updateBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    	ContentValues values = new ContentValues();
        values.put("author", "updated Author");
        values.put("price", 23.33);

        SQLiteDatabase db = helper.getWritableDatabase();
        db.update(MyDBHelper.BOOK_TABLE, values, "id=?", new String[]{"1"});//等价于下面的SQL语句
        //db.execSQL("UPDATE Book SET author=?,price=? WHERE id=?", new Object[]{"updated SQL", 23.33, 1});
        values.clear();
        Toast.makeText(MainActivity.this, "Data updated.", Toast.LENGTH_SHORT).show();
    }
});
3. 3 Delete 删除数据
  • delete()只需要传入表的名称和WHERE条件及相应参数即可;
Button deleteBtn = (Button) findViewById(R.id.delete);
deleteBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = helper.getWritableDatabase();
        db.delete(MyDBHelper.BOOK_TABLE, "id=?", new String[]{"3"});//等价于下面的SQL语句
        //db.execSQL("DELETE FROM Book WHERE id=?;", new Object[]{1});//auto-boxing
    }
});
3. 4 Retrieve 查询数据
  • 查询的结果就是一张表格,需要使用Cursor对象的moveToNext()指向表格的每一行,在每一行中;
Button retrieveBtn = (Button) findViewById(R.id.retrieve);
retrieveBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = helper.getWritableDatabase();
//      Cursor cursor = db.rawQuery("SELECT name, author, price FROM Book",null,null);//与下面的query()等价,然而要求API必须在16以上
        Cursor cursor = db.query(MyDBHelper.BOOK_TABLE, null, null, null, null, null, null);

        if(cursor.moveToNext()){
            do{
                String name = cursor.getString(cursor.getColumnIndex("name"));
                String author = cursor.getString(cursor.getColumnIndex("author"));
                double price = cursor.getDouble(cursor.getColumnIndex("price"));

                Log.i(TAG, name + ", " + author + ", " + price);
            }while(cursor.moveToNext());
        }

    }

});

虽然query()的参数很多,但只要将其视作完整的SELECT语句的拆分,就会很方便理解:
query(from_table, select_columns, where, whereArgs, group_by, having, order_by)

至少出版了一本书且每本书的售价在50以上,返回作者名字及作品数:

SELECT author, count(name)
FROM Book
WHERE price>50
GROUP BY author
HAVING count(name)>1
ORDER BY author

等价于:

db.query(MyDBHelper.BOOK_TABLE, "author, count(name)", "price>?", new String[]{"50"}, "author", "count(name)>1", "author");

Reference 参考

转载于:https://my.oschina.net/SCVTheDefect/blog/522419

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值