android开发笔记之db数据库基本操作

写在前面的话

android开发时,对于db数据库的增删改查的基本操作是一个重点,也是一个难点,我也是经常被这一块弄的有点狼狈不堪。好吧,那我们就好好的会一会这位哥,看一下他为什么这么不好搞。

先声明一下,如果你对db数据库的基本操作不是怎么明白,可以先看一下参考资料中的Sqlite全面学习(一),Sqlite全面学习(二),Sqlite全面学习(三),特别是Sqlite全面学习(二),把db数据的一些基本操作弄明白,然后我们再来实现在android开发时,如何实现对db数据的一些基本操作。

基本接口说明

android开发时,我们主要通过类ContentResolver的query(查询),
insert(增加),update(修改),delete(删除)的4个方法来实现对db数据的基本操作。

那么我们先看一下这四个方法的详细说明:

query–查询方法

(1)query :—-6个参数

Cursor query (Uri uri, 
                String[] projection, 
                String selection, 
                String[] selectionArgs, 
                String sortOrder, 
                CancellationSignal cancellationSignal)

接口的官方说明:

Query the given URI, returning a Cursor over the result set with optional support for cancellation.(这个主要的特点是提供了一个可取消的选项cancellationSignal)

For best performance, the caller should follow these guidelines:
(使用此接口会对机器的性能有比较大的影响,所以要遵守一定的使用规则)

  • Provide an explicit projection, to prevent reading data from storage that aren’t going to be used.(提供明确的projection,而不是把projection设为null,使用时,我们要读取什么值就提供什么projection,这样就不会读取不要使用的数据,提高读取速度。因为我们把projection设为null,这样会读取所有的数据,当然对速度和性能影响非常大)。

  • Use question mark parameter markers such as ‘phone=?’ instead of explicit values in the selection parameter, so that queries that differ only by those values will be recognized as the same for caching purposes.(提供selection的方式为phone=?,不使用明确的phone=xxx,方便查询的缓存目的)

Parameters参数说明

  • uri Uri:

The URI, using the content:// scheme, for the content to retrieve.
数据的URL地址

  • projection String:

A list of which columns to return. Passing null will return all columns, which is inefficient.
返回我们要查询的列的列表,如果设置为null,就返回所有的列表,这是非常低效的,不建议使用。

  • selection String:

A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI.
过滤条件中定义的过滤那些列,就是SQL语句中的where,如果设置为null就返回给定RUL的所有列。鼓励使用?的形式。

  • selectionArgs String:

You may include ?s in selection, which will be replaced by the values from selectionArgs, in the order that they appear in the selection. The values will be bound as Strings.
如果在selection包括?,则selectionArgs 会替换?。selection和selectionArgs组合成过滤条件,以查找我们所需要的db数据库中的数据。

  • sortOrder String:

How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.
这是设置显示的顺序,是SQL中的order,如果设置为null,则显示为默认顺序,这可以就是没有按什么顺序来显示。
顺序有二个:ASC为升序,DESC为降序

  • cancellationSignal CancellationSignal:

A signal to cancel the operation in progress, or null if none. If the operation is canceled, thenOperationCanceledException will be thrown when the query is executed.
在查询进度中的一个可取消查询的信号。如果此查询操作取消,就会导致异常。

对于上面的参数,你如果还是觉得模糊,那我们可以提供一个SQL的查询命令,我们对应来理解:
SQL查询命令:

SELECT column-list FROM table_name [WHERE condition][ORDER BY column1, column2, .. columnN] [ASC | DESC];

那么我们对应table_name就是uri,column-list就是projection,selection和selectionArgs组合成condition,而column1, column2, .. columnN] [ASC | DESC]组合成sortOrder。

我们来一个具体的例子,就会清楚这些对应参数:

我们要从通话日志数据库CallLog.Calls.CONTENT_URI,读取type = Calls.MISSED_TYPE并且new=1的数据,返回Calls.TYPE列,按date desc显示:

SQL命令:

SELECT Calls.TYPE FROM CallLog.Calls.CONTENT_URI [WHERE type = Calls.MISSED_TYPE  and new=1][ORDER BY date] [DESC];

那么,我们对应的调用接口:

Cursor cursor = context.getContentResolver().query(
                CallLog.Calls.CONTENT_URI,
                new String[] {Calls.TYPE},
                " type=? and new=?",
                new String[] {Calls.MISSED_TYPE + "", "1"},
                "date desc"); 

至此,是不是我们对这几个参数就清楚明了了。

Returns 返回值
Cursor:A Cursor object, which is positioned before the first entry, or null

(2)query :—-5个参数(我们使用的比较多)

Cursor query (Uri uri, 
                String[] projection, 
                String selection, 
                String[] selectionArgs, 
                String sortOrder)

此方法和上面的方法一样,只是少了参数cancellationSignal。

弄明白了query方法,那其它三个方法,我们可以水到渠成的就理解了。

insert–插入方法

Uri insert (Uri url, ContentValues values)

官方说明:
Inserts a row into a table at the given URL. If the content provider supports transactions the insertion will be atomic.

Parameters–参数

  • url Uri:

The URL of the table to insert into.

  • values ContentValues:

The initial values for the newly inserted row. The key is the column name for the field. Passing an empty ContentValues will create an empty row.

Returns–返回值
Uri :the URL of the newly created row.

太简单了,都没有什么说的了。

update–更新方法

int update (Uri uri, ContentValues values, String where, String[] selectionArgs)

官方说明:
Update row(s) in a content URI. If the content provider supports transactions the update will be atomic.

Parameters—参数:

  • uri Uri:

The URI to modify.

  • values ContentValues:

The new field values. The key is the column name for the field. A null value will remove an existing field value.

  • where String:

A filter to apply to rows before updating, formatted as an SQL WHERE clause (excluding the WHERE itself).

  • selectionArgs String

Returns–返回值:
int the number of rows updated.

Throws–抛出异常
NullPointerException,if uri or values are null

delete–删除数据

int delete (Uri url, 
                String where, 
                String[] selectionArgs)

官方说明:
Deletes row(s) specified by a content URI. If the content provider supports transactions, the deletion will be atomic.

Parameters–参数:

  • url Uri:

The URL of the row to delete.

  • where String:

A filter to apply to rows before deleting, formatted as an SQL WHERE clause (excluding the WHERE itself).

  • selectionArgs String

Returns–返回值:
int The number of rows deleted.

至此,4个接口已经详细说明了。

使用样例

下面我就写了一个Demo,看看如何来实现db数据库中的增,删,改,查的基本操作。

我们以通话日志数据库为例:

通话记录的db数据库在:

/data/data/com.android.providers.contacts/databases/contacts2.db

calls表—-这为通话日志表

下面二个图是此表的Data和Design显示图:

android开发笔记之db数据库基本操作_第1张图片

帮助类

有了上面的基础,我们可以写一个Help类,实现对此表的增删改查的四个基本操作:

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog;
import android.util.Log;

public class Help {

    public static final String TAG = "Help";
    //这是定义的project,也就是我们要查看的列
    public static final String[] project = new String[]{"_id",
            "number",
            "duration",
            "type",
            "phone_account_address",
            "new",
            "operator"};
    //这是通话日志calls表的URI
    public static final Uri callLogUri = CallLog.Calls.CONTENT_URI;
    //这是我们定义查看的条件,selection 与selectionArgs组合后就是查询的条件,此组合后的条件是duration > 0 并且 type = 2
    public static final String selection = "duration > ?"+"and type = ?";
    //这是条件中的替换selection 中?的值
    public static final String[] selectionArgs = new String[]{"0","2"};
    //这是查询结果显示的顺序,顺序有二种:ASC为升序,DESC为降序
    public static final String sortOrder = "date ASC";


    //查询方法的实现,查询条件中,
    public static void query(Context context) {
        Log.i(TAG, "Help--query");
        Cursor cursor = context.getContentResolver().query(callLogUri,
                project, null, null, sortOrder);//此过滤条件为空,也就是查看所有的数据
                //project, selection, selectionArgs, sortOrder);//此过滤条件为selection和selectionArgs的组合条件,也就是只查看符合条件duration > 0 并且 type = 2
        if (cursor != null) {
            while (cursor.moveToNext()) {
                int id = cursor.getInt(
                        cursor.getColumnIndexOrThrow("_id"));
                String number = cursor.getString(
                        cursor.getColumnIndexOrThrow("number"));
                long duration = cursor.getInt(
                        cursor.getColumnIndexOrThrow("duration"));
                int type = cursor.getInt(
                        cursor.getColumnIndexOrThrow("type"));
                String phone_account_address = cursor.getString(
                        cursor.getColumnIndexOrThrow("phone_account_address"));
                int new_type = cursor.getInt(
                        cursor.getColumnIndexOrThrow("new"));
                String operator = cursor.getString(
                        cursor.getColumnIndexOrThrow("operator"));

                Log.i(TAG, "query:--id:" + id);
                Log.i(TAG, "query:--number:" + number);
                Log.i(TAG, "query:--duration:" + duration);
                Log.i(TAG, "query:--type:" + type);
                Log.i(TAG, "query:--phone_account_address:" + phone_account_address);
                Log.i(TAG, "query:--new_type:" + new_type);
                Log.i(TAG, "query:--operator:" + operator);
                Log.i(TAG, "---------------------------------");
            }
            cursor.close();
        }
    }

    //插入通话日志数据方法
    public static void insert(Context context) {
        Log.i(TAG, "Help--insert");

        ContentValues values = new ContentValues();
        values.put("number","123456789");
        values.put("duration",200);
        values.put("type",0);
        values.put("phone_account_address","+123456789");
        values.put("new",1);
        values.put("operator","CHN-TELE");
        values.put("date",System.currentTimeMillis());

        context.getContentResolver().insert(callLogUri,values);
    }


    //更新符合条件的通话日志数据
    public static void update(Context context) {
        Log.i(TAG, "Help--update");
        //selection_update 和selectionArgs_update 组合的过滤条件是:duration = 0 并且 type = 2 
        final String selection_update = "duration = ?"+"and type = ?";
        final String[] selectionArgs_update = new String[]{"0","2"};
        //将duration改为2,type改为1,date改为当前时间
        ContentValues values = new ContentValues();
        values.put("duration",2);
        values.put("type",1);
        values.put("date",System.currentTimeMillis());

        context.getContentResolver().update(callLogUri,
                values,
                selection_update,
                selectionArgs_update);
    }

    //删除方法
    public static void delete(Context context) {
        Log.i(TAG, "Help--delete");
        //selection_update 和selectionArgs_update 组合的过滤条件是:duration > 0 并且 type = 0
        final String selection_update = "duration > ?"+"and type = ?";
        final String[] selectionArgs_update = new String[]{"0","0"};
        context.getContentResolver().delete(callLogUri,
                selection_update,
                selectionArgs_update);
    }
}

具体实现

(1)我们在界面中成局四个Button,以实现增删改查的四个基本操作:

   <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/query"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:onClick="onClickQuery"
            android:background="@drawable/button_click"
            android:text="@string/query"/>

        <Button
            android:id="@+id/insert"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/query"
            android:onClick="onClickInsert"
            android:layout_marginTop="20dp"
            android:background="@drawable/button_click"
            android:text="@string/insert"/>

        <Button
            android:id="@+id/update"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/insert"
            android:onClick="onClickUpdate"
            android:layout_marginTop="20dp"
            android:background="@drawable/button_click"
            android:text="@string/update"/>
        <Button
            android:id="@+id/delete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/update"
            android:onClick="onClickDelete"
            android:layout_marginTop="20dp"
            android:background="@drawable/button_click"
            android:text="@string/delete"/>

    </RelativeLayout>

(2)在java文件中,我们来实现四个操作,因为有帮助类,所以这个太简单了:

   public void onClickQuery(View view){
        long start = System.currentTimeMillis();
        Help.query(this);
        long end = System.currentTimeMillis();
        Log.i(TAG, "query:--time:" +(end - start));
    }

    public void onClickInsert(View view){
        Help.insert(this);
    }

    public void onClickUpdate(View view){
        Help.update(this);
    }

    public void onClickDelete(View view){
        Help.delete(this);
    }

(3)记得权限有要求,所以,一定要在AndroidManifest.xml文件中添加对应db数据读写的权限:
通话日志的权限:

<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />

(4)给几个log信息,也显示此段逻辑唯代码是可以用的:

查询操作的log:

11-01 09:28:45.747 1277-1277/ I/Help: Help--query
11-01 09:28:45.759 1277-1277/ I/Help: query:--id:1
11-01 09:28:45.760 1277-1277/ I/Help: query:--number:10010
11-01 09:28:45.760 1277-1277/ I/Help: query:--duration:4
11-01 09:28:45.760 1277-1277/ I/Help: query:--type:2
11-01 09:28:45.760 1277-1277/ I/Help: query:--phone_account_address:+8618589014761
11-01 09:28:45.760 1277-1277/ I/Help: query:--new_type:0
11-01 09:28:45.760 1277-1277/ I/Help: query:--operator:CHN-UNICOM
11-01 09:28:45.760 1277-1277/ I/Help: ---------------------------------
11-01 09:28:45.760 1277-1277/ I/Help: query:--id:3
11-01 09:28:45.760 1277-1277/ I/Help: query:--number:10010
11-01 09:28:45.760 1277-1277/ I/Help: query:--duration:154
11-01 09:28:45.760 1277-1277/ I/Help: query:--type:2
11-01 09:28:45.760 1277-1277/ I/Help: query:--phone_account_address:+8618589014734
11-01 09:28:45.760 1277-1277/ I/Help: query:--new_type:0
11-01 09:28:45.760 1277-1277/ I/Help: query:--operator:CHN-UNICOM
11-01 09:28:45.760 1277-1277/ I/Help: ---------------------------------
11-01 09:28:45.760 1277-1277/ I/Help: query:--id:2
11-01 09:28:45.760 1277-1277/ I/Help: query:--number:896
11-01 09:28:45.760 1277-1277/ I/Help: query:--duration:2
11-01 09:28:45.760 1277-1277/ I/Help: query:--type:1
11-01 09:28:45.760 1277-1277/ I/Help: query:--phone_account_address:+8618589014734
11-01 09:28:45.760 1277-1277/ I/Help: query:--new_type:0
11-01 09:28:45.760 1277-1277/ I/Help: query:--operator:CHN-UNICOM
11-01 09:28:45.760 1277-1277/ I/Help: ---------------------------------
11-01 09:28:45.761 1277-1277/ I/Help: query:--id:4
11-01 09:28:45.761 1277-1277/ I/Help: query:--number:75
11-01 09:28:45.761 1277-1277/ I/Help: query:--duration:2
11-01 09:28:45.761 1277-1277/ I/Help: query:--type:1
11-01 09:28:45.761 1277-1277/ I/Help: query:--phone_account_address:+8618589014734
11-01 09:28:45.761 1277-1277/ I/Help: query:--new_type:0
11-01 09:28:45.761 1277-1277/ I/Help: query:--operator:CHN-UNICOM
11-01 09:28:45.761 1277-1277/ I/Help: ---------------------------------
11-01 09:28:45.761 1277-1277/ I/Help: query:--id:5
11-01 09:28:45.761 1277-1277/ I/Help: query:--number:42
11-01 09:28:45.761 1277-1277/ I/Help: query:--duration:2
11-01 09:28:45.761 1277-1277/ I/Help: query:--type:1
11-01 09:28:45.761 1277-1277/ I/Help: query:--phone_account_address:+8618589014734
11-01 09:28:45.761 1277-1277/ I/Help: query:--new_type:0
11-01 09:28:45.761 1277-1277/ I/Help: query:--operator:CHN-UNICOM
11-01 09:28:45.761 1277-1277/ I/Help: ---------------------------------
11-01 09:28:45.764 1277-1277/ I/Help: query:--time:17

文章至此,基本上已经完结了。

亲,你是否对db数据库基本操作已经明白呢?

说实在话,我也是以前对这一块有点恐惧,觉得特别高深,主要是因为自己以前读书时没有系统的学习过db数据库,心里没有底气。

后来,做了一些东西,对db数据库也是有了一定的理解,特别是当我看了
(1)Sqlite全面学习(一)
(2)Sqlite全面学习(二)—–(这个最重要)
(3)Sqlite全面学习(三)
这三篇文章后,我其实基本上心里知道是怎么回事了。

等我再把android官网上的ContentResolver类的query(查询),
insert(增加),update(修改),delete(删除)的4个方法认真的看了一篇后,我基本上已经清楚是怎么回事了。

说实在说,此demo是我直接来code的,基本上没有看什么东西,感觉非常的顺手,有一种水到渠成的感觉。

再也不担心db数据库的基本操作了。

db君,来吧,我们以后可以做朋友了。

参考资料

(1)Sqlite全面学习(一)
http://blog.csdn.net/yanbober/article/details/45567149
(2)Sqlite全面学习(二)
http://blog.csdn.net/yanbober/article/details/45576939
(3)Sqlite全面学习(三)
http://blog.csdn.net/yanbober/article/details/45581751
(4)Android 学习笔记 Contacts (一)ContentResolver query 参数详解
http://blog.csdn.net/wssiqi/article/details/8132603
(5)android开发笔记之获取音频、视频、图片信息
http://blog.csdn.net/hfreeman2008/article/details/11975659
(6)android开发笔记之ContentProvider使用样例一
http://blog.csdn.net/hfreeman2008/article/details/38668417
(7)android开发笔记之ContentProvider使用样例二
http://blog.csdn.net/hfreeman2008/article/details/38713811

你可能感兴趣的:(android,数据库,DB,ContentRes)