`
ping8899
  • 浏览: 42932 次
社区版块
存档分类
最新评论
阅读更多

    <h1>Android开发之数据保存技术(一)</h1>
/*

* Android开发之数据保存技术(一)

* 北京Android俱乐部群:167839253

* Created on: 2011-8-17

* Author: blueeagle

* Email: liujiaxiang@gmail.com

*/



本文主要讲解Android开发的数据保存技术。Android的数据保存技术主要有preference,本地文件,SQLite轻量级数据库,和Content Provider。本文只要讲SQLite和Conent Provider。preference和本地文件,将放在后面讨论。

<h2>SQLite</h2>
Android通过SQLite库提供了完善的关系数据库功能,而没有强加任何额外的限制。通过使用SQLite,可以为每一个应用程序创建独立的关系数据库。

所有的Android数据库都存储在/data/data/<package_name>/databases文件夹下。默认条件下,所有的数据库都是私有的,并且只能被创建它们的应用程序访问。要跨应用程序共享数据库,可以使用内容提供器。

SQLite是一个关系数据管理系统。它被普遍认为是:开源,兼容标准,轻量级,Single-tier。

可以用一个例子来演示SQLite。该例子将记录存储在一个数据库中,然后显示出来。

新建一个HelloSQLite的程序。

需要在某个地方放置该数据库中描述的一些常量,所以要创建一个Constants接口。

代码如下:

/*

* Android开发之数据保存技术(一)

* Constants.java

* Created on: 2011-8-15

* Author: blueeagle

* Email: liujiaxiang@gmail.com

*/



<textarea readonly name="code" class="java">package com.blueeagle;



import android.provider.BaseColumns;

public interface Constants extends BaseColumns {

    /** Called when the activity is first created. */

    public static final String TABLE_NAME = "HelloSQLite";

    public static final String TIME = "time";

    public static final String TITLE = "title";

    }

</textarea><br>
每个事件都将作为HeloSQLite表中的一行进行存储。每行都包含一个_id、time和title列。_id是主键,在扩展的BaseColums接口中声明。time和title分别作为时间和事件标记。



使用SQliteOpenHelper。接下来,创建一个名为SQLiteData的帮助器来表示数据库本身。这个类扩展自Android的SQLiteOpenHelper类,它负责管理数据库的创建和版本。需要做的就是提供一个构造方法并且覆写两个方法。

代码如下:

<textarea readonly name="code" class="java">/*

*  Android开发之数据保存技术(一)

*  MySQLite.java

*  Created on: 2011-8-16

*  Author: blueeagle

*  Email: liujiaxiang@gmail.com

*/

package com.blueeagle;



import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteDatabase.CursorFactory;

import android.database.sqlite.SQLiteOpenHelper;

import static com.blueeagle.Constants.TABLE_NAME;

import static com.blueeagle.Constants.TIME;

import static com.blueeagle.Constants.TITLE;

import static android.provider.BaseColumns._ID;



public class MySQLite extends SQLiteOpenHelper {

   

    private static final String DATABASE_NAME = "MySQLite.db";

    private static final int DATABASE_VERSION = 1;

   

    public MySQLite(Context context, String name, CursorFactory factory,

           int version) {

       super(context, DATABASE_NAME, factory, DATABASE_VERSION);

       // TODO Auto-generated constructor stub

    }



    @Override

    public void onCreate(SQLiteDatabase db) {

       // TODO Auto-generated method stub

       db.execSQL("CREATE TABLE "+ TABLE_NAME+"("+_ID+"INTEGER PRIMARY KEY AUTOINCREMENT,"+TIME+"INTEGER,"+TITLE+"TEXT NOT NULL);");

    }



    @Override

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

       // TODO Auto-generated method stub

       db.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME);

       onCreate(db);

      

    }

}

</textarea><br>
首次访问数据库时,SQLiteOpenHelper将注意到该数据库不存在,并调用onCreate()方法来创建它。

定义Activity主程序。

在HelloSQLite程序中做的第一次尝试是使用本地的SQLite数据库来存储事件,并将这些事件显示为TextView中的一个字符串。

布局xml文件如下:

<textarea readonly name="code" class="html">main.xml

<?xml version="1.0" encoding="utf-8"?>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView 

    android:id="@+id/myText"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    />

</ScrollView>

</textarea><br>

这段代码使用一个ScrollView,以防太多的时间沾满了屏幕。

对于HelloSQLite.java的实现如下所示:相关代码有注释说明。

<textarea readonly name="code" class="java">package com.blueeagle;

/*

*  Android开发之数据保存技术(一)

*  HelloSQLite.java

*  Created on: 2011-8-16

*  Author: blueeagle

*  Email: liujiaxiang@gmail.com

*/



import android.app.Activity;

import android.content.ContentValues;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.os.Bundle;

import android.widget.TextView;

import static com.blueeagle.Constants.TABLE_NAME;

import static com.blueeagle.Constants.TIME;

import static com.blueeagle.Constants.TITLE;

import static android.provider.BaseColumns._ID;



public class HelloSQLite extends Activity {

    /** Called when the activity is first created. */

    private MySQLite mySqlite;

    private static String[] FROM={_ID,TIME,TITLE};

    private static String ORDER_BY = TIME+" DESC";

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        mySqlite = new MySQLite(this);

        try{

        addItem("Hello,Android!");

        Cursor cursor = getItems();

        showItems(cursor);

        }

        finally{

        mySqlite.close();

        }

    }

    //显示查询结果

    private void showItems(Cursor cursor) {

       // TODO Auto-generated method stub

       StringBuilder builder = new StringBuilder("Saved items:\n");

       while(cursor.moveToNext()){

           long id = cursor.getLong(0);

           long time = cursor.getLong(1);

           String title = cursor.getColumnName(2);

           builder.append(id).append(": ");

           builder.append(time).append(": ");

           builder.append(title).append("\n");

       }

       TextView myTextView = (TextView)findViewById(R.id.myText);

       myTextView.setText(builder);

    }

    //此函数接受一个Cursor作为输入并格式化,以便用户能够理解输出的内容

    //查询条目方法

    private Cursor getItems() {

       // TODO Auto-generated method stub

       SQLiteDatabase db = mySqlite.getReadableDatabase();

       Cursor cursor = db.query(TABLE_NAME, FROM, null, null, null, null, ORDER_BY);

       startManagingCursor(cursor);

       return cursor;

    }

    //因为查询不用修改数据库,因此利用只读句柄,然后调用查询的query方法来执行SQL语句,FROM是

    //想要使用的列构成的数组,ORDER_BY告诉SQLite按照从新到旧的顺序返回查询结果。

    //添加条目方法

    private void addItem(String string) {

       // TODO Auto-generated method stub

       SQLiteDatabase db = mySqlite.getWritableDatabase();

       ContentValues values = new ContentValues();

       values.put(TIME, System.currentTimeMillis());

       values.put(TITLE, string);

       db.insert(TABLE_NAME, null, values);

    }

    //因为要修改数据库,所以调用getWritableDatabase()方法来获取数据库的一个写句柄,当然也可以获取

    //到读句柄。

}

</textarea><br>
完成上述文件-》运行,即可看到结果显示出来。这样就完成了第一个Android数据库程序。

当然,这里面需要注意的问题:

1. 新建数据库的问题

新建数据库的时候,会遇到我们用:

db.execSQL("CREATE TABLE "+ TABLE_NAME+"("+_ID+"INTEGER PRIMARY KEY AUTOINCREMENT,"+TIME+"INTEGER,"+TITLE+"TEXT NOT NULL);");

这样一条语句。有时候SQL语句书写错误,比如少一个空格就会引起程序异常退出。这个时候建议在db.execSQL()函数中填写一个字符串变量,然后把自己写的SQL语句赋给字符串变量,在做赋值操作的时候,先打印出来看看,是不是少空格,多+号什么的小错误。

2. 版本号的问题

关于构造函数中的版本号,是有明确的说明的。


<p align="left"> int version) {
super(context, DATABASE_NAME, factory,
DATABASE_VERSION);
这个版本号version当你有新版本的时候,则做更新操作,新版本的版本号将要比老版本高,如果此时修改版本号,不是向高修改,而是向低修改的话,程序就会发生异常了。



3. 数据库文件的问题

对于onCreate()方法,在程序运行的时候,只运行一次,运行的这一次就是去创建数据库。将数据库的文件存储在SD卡中。路径是data/data/包名/databases里。可以在Eclipse里通过DDMS里的File Explorer来查看。当数据库文件存在了以后,则不会再次运行。



完成了上述例子,就算完成了一个数据库的应用。但是如果列表中有数千个或者上百万个事件。程序将运行的非常慢。甚至于耗尽内存。解决办法就是数据绑定。

有了数据绑定,只需要几行代码,就可以将数据连接到视图,从而实现需求。为了演示,我们修改上面的实例。

将主程序HelloSQLite.java继承ListActivity而不是Activity。

将代码修改为如下所示:



<textarea readonly name="code" class="java">package com.blueeagle;

/*

*  Android开发之数据保存技术

*  HelloSQLite.java

*  Created on: 2011-8-16

*  Author: blueeagle

*  Email: liujiaxiang@gmail.com

*/

import android.app.ListActivity;

import android.content.ContentValues;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.os.Bundle;

import android.widget.SimpleCursorAdapter;

import static com.blueeagle.Constants.TABLE_NAME;

import static com.blueeagle.Constants.TIME;

import static com.blueeagle.Constants.TITLE;

import static android.provider.BaseColumns._ID;



public class HelloSQLite extends ListActivity {

    /** Called when the activity is first created. */

    private MySQLite mySqlite;

    private static String[] FROM={_ID,TIME,TITLE};

    private static String ORDER_BY = TIME+" DESC";

    //@Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        mySqlite = new MySQLite(this);

        try{

        addItem("Hello,Android!");

        Cursor cursor = getItems();

        showItems(cursor);

        }

        finally{

        mySqlite.close();

        }

    }

    private static int[] TO = {R.id.rowid,R.id.time,R.id.title};

    private void showItems(Cursor cursor) {

    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.item,cursor,FROM,TO);

    //这里有必要说明一下SimpleCursorAdapter构造函数的5个参数。1.对应于当前Activity的引用,2.一个资源,它定义一个列表条目的视图,

    //3.数据集光标,4.一组列名称,数据来源于这些列。5.视图列表,这是数据的目的地。

    setListAdapter(adapter);

   

    }

    private Cursor getItems() {

       SQLiteDatabase db = mySqlite.getReadableDatabase();

       Cursor cursor = db.query(TABLE_NAME, FROM, null, null, null, null, ORDER_BY);

       startManagingCursor(cursor);

       return cursor;

    }

    private void addItem(String string) {

       // TODO Auto-generated method stub

       SQLiteDatabase db = mySqlite.getWritableDatabase();

       ContentValues values = new ContentValues();

       values.put(TIME, System.currentTimeMillis());

       values.put(TITLE, string);

       db.insert(TABLE_NAME, null, values);

    }

}

</textarea><br>
将main.xml修改成如下形式:

<textarea readonly name="code" class="html"><?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<ListView

android:id="@android:id/list"

android:layout_height="wrap_content"

android:layout_width="wrap_content">

</ListView>

<TextView

android:id="@android:id/empty"

android:layout_height="wrap_content"

android:layout_width="wrap_content"

android:text="empty!">

</TextView>

</LinearLayout>

</textarea><br>

增加item.xml为如下:

<textarea readonly name="code" class="html"><?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="horizontal"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:padding="10sp"

    >

<TextView

android:id="@+id/rowid"

android:layout_height="wrap_content"

android:layout_width="wrap_content">

</TextView>

<TextView

android:id="@+id/rowidcolon"

android:layout_height="wrap_content"

android:layout_width="wrap_content"

android:text=":"

android:layout_toRightOf="@id/rowid">

</TextView>

<TextView

android:id="@+id/time"

android:layout_height="wrap_content"

android:layout_width="wrap_content"

android:layout_toRightOf="@id/rowidcolon">

</TextView>

<TextView

android:id="@+id/timecolon"

android:layout_height="wrap_content"

android:layout_width="wrap_content"

android:text=":"

android:layout_toRightOf="@id/time">

</TextView>

<TextView

android:id="@+id/title"

android:layout_height="fill_parent"

android:layout_width="wrap_content"

android:textStyle="italic"

android:ellipsize="end"

android:singleLine="true"

android:layout_toRightOf="@id/timecolon">

</TextView>

</RelativeLayout>

</textarea><br>
运行结果如图所示。

<img src="http://hi.csdn.net/attachment/201108/17/0_1313565594vM3N.gif" alt="">

当然,这只是一个DEMO,用来展示如何使用SQLite,这个DEMO存在一些问题。其他应用程序都不能向事件数据库添加内容,甚至于无法看这些事件。那么针对这一点,引出了Android里的内容提供器,即ContentProvider。

<h2>内容提供器</h2>
在Android安全模型中,一个应用程序编写的文件无法被其他任何应用程序所读写。每个应用程序都有自己的Linux用户ID和数据目录,以及其受保护的内存空间。Android程序可以通过下面两种方式进行彼此间的通信。

第一种是IPC(Inter-Process Communication,进程间通信):一个进程使用AIDL(Android Interface Definition Language,接口定义语言)和IBinder接口声明一个任意的API。调用该API时,将在进程间安全且有效地队参数进行编组。这项先进技术用于对后台Service线程进行远程过程调用。

第二种就是ContentProvider:进程在系统中将他们本身注册为某些数据类型的提供者。请求该信息时,Android就会通过一个固定的API调用这些进程,以它们认为合适的方式查询或者修改内容。

ContentProvider管理的任何信息部分都通过一个URI来寻址,这个URI类似于以下形式:content://authority/path/id

其中content://是标准要求的前缀。authority是提供者的名称,建议使用完全限定包名称,避免出现名称冲突。Path是提供者内部的一个虚拟目录,用于标识被请求的数据类型。Id是被请求的特定记录的主键,要请求获得具有特定类型的所有记录,可以省略此参数以及后面的斜杠。

Android已经内置提供了几个提供者,包括:

content://browser;

content://contacts;

content://media;

content://settings。

下面我们就来演示如何使用内容提供器。

将HelloSQLite程序改为使用内容提供器的。对于HelloSQLite的提供者,下面都是有效的URI:

content://com.blueeagle.HelloSQLite/3 ——表示取id为3的数据

content://com.blueeagle.HelloSQLite/ ——表示取所有数据



首先需要向Contants.java添加两个常量:


public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME);



接下来可以对HelloSQLite类做一些修改:

代码如下:

<textarea readonly name="code" class="java">package com.blueeagle;

/*

*  Android开发之数据保存技术(一)

*  HelloSQLite.java

*  Created on: 2011-8-16

*  Author: blueeagle

*  Email: liujiaxiang@gmail.com

*/



import android.app.ListActivity;

import android.content.ContentValues;

import android.database.Cursor;

import android.os.Bundle;

import android.widget.SimpleCursorAdapter;

import static com.blueeagle.Constants.TIME;

import static com.blueeagle.Constants.TITLE;

import static com.blueeagle.Constants.CONTENT_URI;

import static android.provider.BaseColumns._ID;



public class HelloSQLite extends ListActivity {

    /** Called when the activity is first created. */

    //private MySQLite mySqlite;

    private static String[] FROM = {_ID,TIME,TITLE};

    private static String ORDER_BY = TIME+" DESC";

    //@Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        addItem("Hello,Android!");

        Cursor cursor = getItems();

        showItems(cursor);

    }

    private static int[] TO = {R.id.rowid,R.id.time,R.id.title};

   

//显示查询结果

    private void showItems(Cursor cursor) {

       // TODO Auto-generated method stub

    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.item,cursor,FROM,TO);

    setListAdapter(adapter);

    }

    //使用ContentProvider时,geiItems方法也化简了

    private Cursor getItems() {

       return managedQuery(CONTENT_URI,FROM,null,null,ORDER_BY);

    }

    //此处使用Activity.managedQuery()方法,将内容URI,感兴趣的列表和应该使用的排序顺序传递给该方法。

    private void addItem(String string) {

       ContentValues values = new ContentValues();

       values.put(TIME, System.currentTimeMillis());

       values.put(TITLE, string);

       getContentResolver().insert(CONTENT_URI, values);

    }

    //没有了对getWriteableDatabase()的调用,对insertOrThrow的调用替换成了getContentResolver().insert(CONTENT_URI, values)

    //我们使用了一个URI而不是用数据库句柄。

}

</textarea><br>

下面就是实现ContentProvider

ContentProvider是一个类似于Activity的高级对象,需要向系统进行声明。因此,实现ContentProvider的第一步是将其添加到AndroidManifest.xml文件中的<activity>标签之前。

其中android:name是类名,android:authorities是在内容URI中使用的字符串。接下来创建我们自己的ContentProvider类,为继承类。ContentProvider创建后就会被调用:public boolean onCreate()ContentProvider类中有6个继承而来的方法,需要实现:

具体来说需要实现ContentProvider 类中的6个抽象方法。 <br>
Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):将查询的数据以Cursor 对象的形式返回。
<br>
Uri insert(Uri uri, ContentValues values):向 Content Provider中插入新数据记录,ContentValues 为数据记录的列名和列值映射。
<br>
int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):更新Content Provider中已存在的数据记录。


int delete(Uri uri, String selection, String[] selectionArgs):从Content Provider中删除数据记录。

String getType(Uri uri):返回Content Provider中的数据( MIME )类型。

boolean onCreate():当 Content Provider 启动时被调用。

定义一个 URI 类型的静态常量,命名为CONTENT_URI。 必须为该常量对象定义一个唯一的URI字符串,一般的做法是将 ContentProvider子类的全称类名作为URI字符串。

定义每个字段的列名,如果采用的数据库存储系统为SQLite 数据库,数据表列名可以采用数据库中表的列名。不管数据表中有没有其他的唯一标识一个记录的字段,都应该定义一个"_id"字段 来唯一标识一个记录。模式使用 "INTEGER PRIMARY KEY AUTOINCREMENT" 自动更新 一般将这些列名字符串定义为静态常量, 如"_id"字段名定义为一个名为"_ID" 值为 "_id" 的静态字符串对象。

创建好的一个Content Provider必须在AndroidManifest.xml中声明。

<p align="left"> <provider android:name=".ItemsProvider"
android:authorities="com.blueeagle" />

其中name属性为ContentProvider 子类的全称类名,authorities 属性唯一标识了一个ContentProvider。还可以通过 setReadPermission() 和 setWritePermission() 来设置其操作权限。当然也可以再上面的 xml中加入 android:readPermission 或者 android: writePermission属性来控制其权限。
<br>注意:因为ContentProvider可能被不同的进程和线程调用,所以这些方法必须是线程安全的。

然后需要使用UriMatcher,用于匹配Uri。<br>
用法如下:<br>
首先把需要匹配Uri路径全部给注册上:

对于Uri:

什么是URI?将其分为A,B,C,D 4个部分:

A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"

B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称 ;"content://hx.android.text.myprovider"

C:路径,不知道是不是路径,通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://hx.android.text.myprovider/tablename"

D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示数据id


注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,例如匹配content://com.blueeagle路径,返回的匹配码为1。


//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码<br>
UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

//添加需要匹配的uri,如果匹配就会返回匹配码<br>
//如果match()方法匹配content://com.blueeagle路径,返回匹配码为1<br>
sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite”, 1);

//如果match()方法匹配content://com.blueeagle/ ***路径,返回匹配码为2<br>
//#号为通配符<br>
sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite/#”, 2);

switch(sUriMatcher.match(Uri.parse("content://com.blueeagle /***"))) {<br>
case 1 break;<br>
case 2 break;<br>
default:<br>
//不匹配 break;<br>
}

自定义的contentprovider如下:

ItemsProvider.java

<textarea readonly name="code" class="java">package com.blueeagle;

/*

*  Android开发之数据保存技术(一)

*  ItemsProvider.java

*  Created on: 2011-8-16

*  Author: blueeagle

*  Email: liujiaxiang@gmail.com

*/



import android.content.ContentProvider;

import android.content.ContentUris;

import android.content.ContentValues;

import android.content.UriMatcher;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.net.Uri;

import android.text.TextUtils;

import static com.blueeagle.Constants.CONTENT_URI;

import static com.blueeagle.Constants.TABLE_NAME;

import static com.blueeagle.Constants.AUTHORITY;

import static android.provider.BaseColumns._ID;



public class ItemsProvider extends ContentProvider {

   

    private static final int ITEMS = 1;

    private static final int ITEMS_ID = 2;

       /** The MIME type of a directory of items */

       private static final String CONTENT_TYPE

          = "vnd.android.cursor.dir/vnd.com.blueeagle";

       /** The MIME type of a single item */

       private static final String CONTENT_ITEM_TYPE

          = "vnd.android.cursor.item/vnd.com.blueeagle";

      

       private MySQLite myDataBase ;

       private UriMatcher myUriMatcher;

      

       @Override

       public boolean onCreate() {

          myUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

          myUriMatcher.addURI(AUTHORITY, "HelloSQLite", ITEMS);

          myUriMatcher.addURI(AUTHORITY, "HelloSQLite/#", ITEMS_ID);

          myDataBase = new MySQLite(getContext());

          return true;

       }

    @Override

    public int delete(Uri uri, String selection,

       // TODO Auto-generated method stub

        String[] selectionArgs) {

            SQLiteDatabase db = myDataBase.getWritableDatabase();

            int count;

            switch (myUriMatcher.match(uri)) {

            case ITEMS:

               count = db.delete(TABLE_NAME, selection, selectionArgs);

               break;

            case ITEMS_ID:

               long id = Long.parseLong(uri.getPathSegments().get(1));

               count = db.delete(TABLE_NAME, appendRowId(selection, id),

                     selectionArgs);

               break;

            default:

               throw new IllegalArgumentException("Unknown URI " + uri);

            }

            // Notify any watchers of the change

            getContext().getContentResolver().notifyChange(uri, null);

            return count;

    }

    @Override

    public String getType(Uri uri) {

       // TODO Auto-generated method stub

          switch (myUriMatcher.match(uri)) {

          case ITEMS:

             return CONTENT_TYPE;

          case ITEMS_ID:

             return CONTENT_ITEM_TYPE;

          default:

             throw new IllegalArgumentException("Unknown URI " + uri);

          }

    }

    @Override

    public Uri insert(Uri uri, ContentValues values) {

       // TODO Auto-generated method stub

          SQLiteDatabase db = myDataBase.getWritableDatabase();

          // Validate the requested uri

          if (myUriMatcher.match(uri) != ITEMS) {

             throw new IllegalArgumentException("Unknown URI " + uri);

          }

          // Insert into database

          long id = db.insertOrThrow(TABLE_NAME, null, values);

          // Notify any watchers of the change

          Uri newUri = ContentUris.withAppendedId(CONTENT_URI, id);

          getContext().getContentResolver().notifyChange(newUri, null);

          return newUri;

    }

    @Override

    public Cursor query(Uri uri, String[] projection,

             String selection, String[] selectionArgs, String orderBy) {

       // TODO Auto-generated method stub

          if (myUriMatcher.match(uri) == ITEMS_ID) {

              long id = Long.parseLong(uri.getPathSegments().get(1));

              selection = appendRowId(selection, id);

          }

              // Get the database and run the query

              SQLiteDatabase db = myDataBase.getReadableDatabase();

              Cursor cursor = db.query(TABLE_NAME, projection, selection,

                    selectionArgs, null, null, orderBy);

              // Tell the cursor what uri to watch, so it knows when its

              // source data changes

              cursor.setNotificationUri(getContext().getContentResolver(),

                    uri);

              return cursor;

          }

    private String appendRowId(String selection, long id) {

       // TODO Auto-generated method stub

          return _ID + "=" + id

          + (!TextUtils.isEmpty(selection)

                ? " AND (" + selection + ')'

                : "");

    }

    @Override

    public int update(Uri uri, ContentValues values, String selection,

           String[] selectionArgs) {

       // TODO Auto-generated method stub

          SQLiteDatabase db = myDataBase.getWritableDatabase();

          int count;

          switch (myUriMatcher.match(uri)) {

          case ITEMS:

             count = db.update(TABLE_NAME, values, selection,

                   selectionArgs);

             break;

          case ITEMS_ID:

             long id = Long.parseLong(uri.getPathSegments().get(1));

             count = db.update(TABLE_NAME, values, appendRowId(

                   selection, id), selectionArgs);

             break;

          default:

             throw new IllegalArgumentException("Unknown URI " + uri);

          }

          // Notify any watchers of the change

          getContext().getContentResolver().notifyChange(uri, null);

          return count;

    }

}

</textarea><br>
总结一下,创建一个新的内容提供器。

1.通过扩展抽象类ContentProvider可以创建新的内容提供器。重写onCreate方法来打开或者初始化将要使用这个新的提供器来提供底层数据源。

2.还应该提供那些用来返回指向这个提供器的完整的URI的公共静态CONTENT_URI变量。提供器之间的内容URI应该是唯一的,所以最好的做法是使URI路径以包名为基础。

定义一个内容提供器URI一般的形式为:

content://com.pakagename/datapath

例如:content://com.blueeagle/items

或者:content://com.blueeagle./items/3

内容URI可以表示为这两种形式中的任意一种形式。前面的一种URI表示对那种类型中所有的值的请求,后面附加一个/3的表示对一条记录的请求(这里请求的是记录3)。这两种形式来访问提供器都是可行的。

完成这项工作最简单的方式是使用一个UriMatcher。当通过内容解析器来访问内容提供器的时候,可以配置UriMathcer来解析URI以确定它们的形式。就像前文说的那样。

 
0
0
分享到:
评论

相关推荐

    Android之SharedPreferences数据保存

    在Android开发中,有时候有些数据需要保存,在下次打开能够使用,那么如何保存呢?本资源通过一个例子使用SharedPreferences保存数据。

    老罗android开发视频教程全集百度网盘下载

    数据储存与文件操作、对话框、通知、菜单、 LoaderManager异步加载、多线程(AsyncTask与Handler)、 百度地图等十五个模块,一共102集。 本网盘分享章节编号是按照视频更新的先后顺序编号的,具体学习可参考如下...

    Android开发之数据存储的四种方式之SharedPreferences

    Android项目开发中使用的数据存储方式有:网络存储、sqlite存储、File存储和SharedPreferences存储,四种存储方式对应的Demo别人是NetworkDemo、SqliteDemo、FileDemo和SharedPreferencesDemo,根据应用的场景选择...

    Android软件开发之数据的新建 储存 读取 删除源码

    雨松MOMO带你做软件 Android软件开发之数据的新建 储存 读取 删除源码 欢迎大家下载阅读。

    Android开发实验---通讯录.docx

    Android开发实验---通讯录 实验报告 通讯录 姓名: 学号: 课程名称: 移动应用开发 所在学院: 信息科学与工程学院 专业班级: 计算机 任课教师: Android开发实验---通讯录全文共25页,当前为第1页。 Android开发...

    新版Android开发教程.rar

    这一联盟将会支持 Google 发布的 Android 手机操作系统或者应用软件,共同开发名为 Android 的 开 放源代码的移动系统。开放手机联盟包括手机制造商、手机芯片厂商和移动运营商几类。目前,联盟成员 数 量已经达到了...

    AndroidAPI之数据储存[定义].pdf

    AndroidAPI之数据储存[定义].pdf

    上海建桥学院-移动应用开发-实验报告3-Android数据存储

    实验三 Android数据存储 一、实验目的及要求 (1) 掌握Android的SharedPreferences的使用 (2) 掌握在Android中使用SQLite的方法 二、实验内容及步骤 任务:根据下述要求实现对应程序 1、 根据所给界面1完成登入...

    android 视频录制 并保存到本地

    android 视频录制 并且保存到本地 注意 保存到sd卡 必须 自己手动创建文件夹 PathUtil 类 dir 的参数 自己改

    android开发实例大全_王东华

    实例058: 使用文件保存数据 188 实例059: 将网上的图片保存到SD卡并在 手机中显示出来 190 实例060: 保存联系人信息 194 第5章 电话和短信实例集锦 197 实例061: 编写一个拨号程序 197 实例062: 发送一条短信...

    Android高级编程--源代码

    6.1 Android中的数据保存技术 160 6.2 保存简单的应用程序数据 160 6.2.1 创建和保存preference 160 6.2.2 检索共享的preference 161 6.2.3 保存活动状态 162 6.2.4 为地震查看器创建一个Preference页 165 ...

    android游戏开发毕业论文

    本科毕业设计论文,android解密游戏开发,从 1 绪论 1.1 课题的背景及意义1.2 研究现状1.3 论文主要工作1.4 论文结构安排 2 Android平台研究2.1 Android特征 2.2 Android应用的构成2.2.1 活动2.2.2 意图接收器2.2.3...

    android 超简单的数据保存与读取 一行代码搞定数据保存与读取

    android 超简单的数据保存与读取 一行代码搞定数据保存与读取

    android开发秘籍

    android开发秘籍完整版清晰版 第1 章 android 概述 1 1.1 android 演化史 1 1.2 android 的两面性 2 1.3 运行android 的设备 2 1.3.1 htc 系列机型 4 1.3.2 摩托罗拉系列机型 4 1.3.3 三星系列机型 4 1.3.4 ...

    Android Studio如何获取SQLite数据并显示到ListView上

    SQLite是一个轻量级的数据库,它能将数据保存到你的手机,但缺点是一旦软件卸载所有数据将一同被销毁。所以要根据自己的项目需要选择性的使用。下面要演示将SQLite中的数据提取出来。 首先定义一个类用来实例化...

    android开发——简易计算器的设计报告.doc

    一、实训目的 1、了解Android系统,学会Android开发环境的搭建。 2、了解Eclipse,学会用Eclipse和Java 开发一个Android程序。 3、进一步巩固课堂上所学到的知识,深刻把握Java语言的重要概念及其面向对象的特性 ,...

    Android传感器测试,包括加速度、方向等数据,保存到数据库.zip

    Android传感器测试,包括加速度、方向等数据,保存到数据库,可导出到Excel以便分析研究 软件开发设计:PHP、QT、应用软件开发、系统软件开发、移动应用开发、网站开发C++、Java、python、web、C#等语言的项目开发与...

    Android 将数据写入到Word中

    该项目主要功能是将数据写入到word中,需要的同志可以下载看看,项目中需要的jar包可在 http://download.csdn.net/detail/linzhenxiang123/9717253 进行下载

Global site tag (gtag.js) - Google Analytics