Android 数据持久化(SQLite数据存储)

来源:互联网 发布:wow60 n服数据库 编辑:程序博客网 时间:2024/05/14 21:18

Android 数据持久化(数据存储)—— 数据库存储

任何一个应用程序,其实都是不停的与数据打交道,我们聊 QQ、看新闻、刷微博所关心的都是里面的数据,没有数据的应用程序就变成了一个空壳子,对用户来说没有任何实际用途。那么这些数据都是从哪来的呢?现在多数的数据基本都是由用户产生的了,比如你发微博、评论新闻,其实都是在产生数据。

数据分为两种:瞬时数据与永久数据。瞬时数据,就是存储在内存中,可能会因为程序关闭、断电、回收而丢失的数据;永久数据,就是保存在存储设备中,处于持久状态的数据。

数据持久化技术,则是提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换。说了这么多,然并卵,它跟本文的主题有什么关系呢,Android 系统提供了三种方式来实现数据持久化,即文件存储、SharedPreference 存储、数据库存储。本文主要介绍数据库存储方式,即 Android 内置的 SQLite 数据库。

源代码下载:http://download.csdn.net/download/xwdoor/9433056

创建实体类 Book

数据库主要存储书籍信息,需要创建一个实体类 Book,数据表中的列明也作为常量保存在实体类中。

    public class Book {        public static final String BOOK_NAME = "name";        public static final String BOOK_AUTHOR = "author";        public static final String BOOK_PAGES = "pages";        public static final String BOOK_PRICE = "price";        public int id;        public String name;        public String author;        public int pages;        public float price;        public Book() {        }        public Book(String name, String author, int pages, float price) {            this.name = name;            this.author = author;            this.pages = pages;            this.price = price;        }        @Override        public String toString() {            return "Book{" +                    "name='" + name + '\'' +                    ", author='" + author + '\'' +                    ", pages=" + pages +                    ", price=" + price +                    '}';        }    }

创建 SQLite 数据库

Android 为了让我们能够更加方便地管理数据库,专门提供了一个 SQLiteOpenHelper 帮助类, 借助这个类就可以非常简单地对数据库进行创建和升级。既然有好东西可以直接使用,那我们自然要尝试一下了,下面我就将对 SQLiteOpenHelper 的基本用法进行介绍。

SQLiteOpenHelper 是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper 中有两个抽象方法,分别是onCreate()和 onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。

创建类 BookDbHelper 继承自 SQLiteOpenHelper,这里介绍一下它的构造方法,SQLiteOpenHelper 中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收四个参数:

  • 第一个参数是 Context,这个没什么好说的,必须要有它才能对数据库进行操作。
  • 第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。
  • 第三个参数允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null。
  • 第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。

对了,实例化 BookDbHelper 对象后,需要调用 getReadableDatabase() 或 getWritableDatabase() 方法,才能够创建数据库,即执行 onCreate() 方法里面的代码。

    public class BookDbHelper extends SQLiteOpenHelper {        public static final String TABLE_BOOK = "Book";        public static final String CREATE_BOOK = "create table " + TABLE_BOOK + " ("                + "id integer primary key autoincrement, "                + "author text, "                + "price real, "                + "pages integer, "                + "name text)";        public BookDbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {            super(context, name, factory, version);        }        public BookDbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {            super(context, name, factory, version, errorHandler);        }        @Override        public void onCreate(SQLiteDatabase sqLiteDatabase) {            //创建数据表            sqLiteDatabase.execSQL(CREATE_BOOK);        }        @Override        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {            switch (oldVersion) {                case 1:                default:            }        }    }

添加数据

对数据进行的操作也就无非四种,即 CRUD。其中 C 代表添加(Create) ,R 代表查询(Retrieve) ,U 代表更新(Update) ,D 代表删除(Delete) 。如果熟悉 SQL 语言的话,一定会知道添加数据时使用 insert,查询数据时使用 select,更新数据时使用 update,删除数据时使用 delete。但是开发者的水平总会是参差不齐的,未必每一个人都能非常熟悉地使用 SQL 语言,因此 Android也是提供了一系列的辅助性方法,使得在 Android 中即使不去编写 SQL 语句,也能轻松完成所有的 CRUD 操作。

那么我们一个一个功能地看,首先学习一下如何向数据库的表中添加数据吧。SQLiteDatabase 中提供了一个 insert()方法,这个方法就是专门用于添加数据的。它接收三个参数:

  • 第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字。
  • 第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值 NULL,一般我们用不到这个功能,直接传入 null 即可。
  • 第三个参数是一个 ContentValues 对象,它提供了一系列的 put() 方法重载,用于向 ContentValues 中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。

我对数据表的增删改查进行了简单的封装,集成在了 DbUtils 类中,添加数据的代码很简单,调用 insert() 方法即可:

    //添加数据    public long addBook(String author, float price, int pages, String name) {        SQLiteDatabase dbWrite = mBookDb.getWritableDatabase();        ContentValues values = new ContentValues();        values.put(Book.BOOK_AUTHOR, author);        values.put(Book.BOOK_PRICE, price);        values.put(Book.BOOK_PAGES, pages);        values.put(Book.BOOK_NAME, name);        return dbWrite.insert(BookDbHelper.TABLE_BOOK, null, values);    }

更新(修改)数据

接下来看看怎样才能修改表中已有的数据。SQLiteDatabase 中也是提供了一个非常好用的 update() 方法用于对数据进行更新,这个方法接收四个参数:

  • 第一个参数和 insert()方法一样,也是表名,在这里指定去更新哪张表里的数据。
  • 第二个参数是 ContentValues 对象,要把更新数据在这里组装进去。
  • 第三、第四个参数用于去约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。
    //根据书名修改价格    public int updatePriceByName(String name, float price) {        SQLiteDatabase dbWrite = mBookDb.getWritableDatabase();        ContentValues values = new ContentValues();        values.put(Book.BOOK_PRICE, price);        String whereClause = Book.BOOK_NAME + "=?";        return dbWrite.update(BookDbHelper.TABLE_BOOK, values, whereClause, new String[]{name});    }

删除数据

有了上面的经验,删除数据就是小菜一碟了,SQLiteDatabase 中提供了一个 delete() 方法专门用于删除数据,这个方法接收三个参数:

  • 第一个参数仍然是表名,这个已经没什么好说的了。
  • 第二、第三个参数又是用于去约束删除某一行或某几行的数据,不指定的话默认就是删除所有行。
    //根据书名删除书籍    public int deleteBookByName(String name) {        SQLiteDatabase dbWrite = mBookDb.getWritableDatabase();        String whereClause = Book.BOOK_NAME + "=?";        return dbWrite.delete(BookDbHelper.TABLE_BOOK, whereClause, new String[]{name});    }    //删除所有书籍    public int deleteAllBook() {        SQLiteDatabase dbWrite = mBookDb.getWritableDatabase();        return dbWrite.delete(BookDbHelper.TABLE_BOOK, null,null);    }

查询数据

重头戏来了,所有保存的数据都是为了以后方便读取,所以查询数据是 CRUD 操作中最复杂的一种。SQLiteDatabase 中提供了一个 query() 方法用于对数据进行查询。这个方法的参数非常复杂,最短的一个方法重载也需要传入七个参数。我们先来看一下这七个参数各自的含义吧:

  • 第一个参数不用说,当然还是表名,表示我们希望从哪张表中查询数据。
  • 第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列。
  • 第三、第四个参数用于去约束查询某一行或某几行的数据,不指定则默认是查询所有行的数据。
  • 第五个参数用于指定需要去 group by 的列,不指定则表示不对查询结果进行 group by 操作。
  • 第六个参数用于对 group by 之后的数据进行进一步的过滤,不指定则表示不进行过滤。
  • 第七个参数用于指定查询结果的排序方式,不指定则表示使用默认的排序方式。

其实说白了,query() 方法只是将 SQL 语法的几个关键字用参数的形式进行分离与封装罢了。其他几个 query() 方法大同小异,有兴趣的可以试试,反正我只用这一种,不管你信不信,反正我是信了…

    //查询所有书籍    public List<Book> queryBook() {        List<Book> books = new ArrayList<>();        SQLiteDatabase dbWrite = mBookDb.getWritableDatabase();        Cursor cursor = dbWrite.query(BookDbHelper.TABLE_BOOK, null, null, null, null, null, null);        if (cursor.moveToFirst()) {            do {                Book book = new Book();                book.author = cursor.getString(cursor.getColumnIndex(Book.BOOK_AUTHOR));                book.name = cursor.getString(cursor.getColumnIndex(Book.BOOK_NAME));                book.price = cursor.getFloat(cursor.getColumnIndex(Book.BOOK_PRICE));                book.pages = cursor.getInt(cursor.getColumnIndex(Book.BOOK_PAGES));                books.add(book);            } while (cursor.moveToNext());        }        //关键:一定要关闭cursor        cursor.close();        return books;    }

调试

接下来就是如何调用与测试了,简单起见,在界面中显示四个按钮,分别对应 CRUD 操作,下面给出后台调用代码:

    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_add_book:                //添加书籍                for (Book book : mBooks) {                    long r = mDbUtils.addBook(book.author, book.price, book.pages, book.name);                    Log.i("123123", r + "");                }                break;            case R.id.btn_update_book:                //更新书籍价格                int result = mDbUtils.updatePriceByName(mBooks.get(1).name, 33.3f);                Log.i("123123", result + "");                break;            case R.id.btn_delete_book:                //删除书籍                result = mDbUtils.deleteBookByName(mBooks.get(1).name);                Log.i("123123", result + "");                break;            case R.id.btn_query_book:                //查询所有书籍                List<Book> books = mDbUtils.queryBook();                for (Book book : books) {                    tvBooks.append(book + "\n");                }                break;        }    }

总结

本来是想写一篇关于 ContentProvider 的文章,但是写的时候发现需要用到数据存储方面的知识,于是就复习了一下知识点,诞生了这篇文章。途中遇到一个问题:写完代码调试的时候,点击添加之后,能够查询出数据,但是更新和删除操作没有作用,查询的结果没有变化,那时候是晚上在家,看了近一个小时,没有找到问题,就气恼的关了电脑,看书去了。第二天到公司重新调试后,发现是查询的代码写错了,查询后遍历的列表对象写错了,难怪查询结果没有任何变化了。所以说,面临任何问题都不能急躁。
对了,写这篇文章的时候,也去翻了翻《第一行代码》这本书,本文中很多描述文字,也是摘抄来的。

源代码下载:http://download.csdn.net/download/xwdoor/9433056

0 0