您的位置:首页 > 移动开发 > Android开发

Android开发之数据保存技术

2011-08-17 22:52 513 查看
 
       本文主要讲解Android开发的数据保存技术。Android的数据保存技术主要有preference,本地文件,SQLite轻量级数据库,和Content Provider。本文只要讲SQLite和Conent Provider。preference和本地文件,将放在后面讨论。

SQLite

       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

 */

 

view plaincopy to clipboardprint?

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";  
  
    }  

view plaincopy to clipboardprint?

/* 
 
 *  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);  
  
         
  
    }  
  
}  

/*

*  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);

}

}


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

定义Activity主程序。

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

布局xml文件如下:

view plaincopy to clipboardprint?

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>  

view plaincopy to clipboardprint?

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()方法来获取数据库的一个写句柄,当然也可以获取
  
  
    //到读句柄。   
  
}  

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()方法来获取数据库的一个写句柄,当然也可以获取

//到读句柄。

}


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

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

1.       新建数据库的问题

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

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

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

2.       版本号的问题

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

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

 

3.       数据库文件的问题

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

 

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

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

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

将代码修改为如下所示:

 

view plaincopy to clipboardprint?

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);  
  
    }  
  
}  

view plaincopy to clipboardprint?

<?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>  

<?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>


 

增加item.xml为如下:

view plaincopy to clipboardprint?

<?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>  

view plaincopy to clipboardprint?

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而不是用数据库句柄。
  
  
}  

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而不是用数据库句柄。

}


 

下面就是实现ContentProvider

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

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

具体来说需要实现ContentProvider 类中的6个抽象方法。

       Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):将查询的数据以Cursor 对象的形式返回。

        Uri insert(Uri uri, ContentValues values):向 Content Provider中插入新数据记录,ContentValues 为数据记录的列名和列值映射。

        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中声明。

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

其中name属性为ContentProvider 子类的全称类名,authorities 属性唯一标识了一个ContentProvider。还可以通过 setReadPermission() 和 setWritePermission() 来设置其操作权限。当然也可以再上面的 xml中加入 android:readPermission 或者 android: writePermission属性来控制其权限。

 注意:因为ContentProvider可能被不同的进程和线程调用,所以这些方法必须是线程安全的。

然后需要使用UriMatcher,用于匹配Uri。

用法如下: 

首先把需要匹配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表示不匹配任何路径的返回码 

UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

//添加需要匹配的uri,如果匹配就会返回匹配码 

//如果match()方法匹配content://com.blueeagle路径,返回匹配码为1 

sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite”, 1);

//如果match()方法匹配content://com.blueeagle/ ***路径,返回匹配码为2

//#号为通配符 

sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite/#”, 2);

switch(sUriMatcher.match(Uri.parse("content://com.blueeagle /***"))) {

 case 1 break;

 case 2 break; 

default:

//不匹配 break; 

}

自定义的contentprovider如下:

ItemsProvider.java

view plaincopy to clipboardprint?

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;  
  
    }  
  
}  

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;

}

}

总结一下,创建一个新的内容提供器。

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以确定它们的形式。就像前文说的那样。

出自:http://blog.csdn.net/redoffice/article/details/6695345
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐