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

再探Android多应用间数据共享机制,自定义ContentProvider

2012-08-09 17:47 627 查看


再探Android多应用间数据共享机制,自定义ContentProvider

Android中的ContentProvider是一种多应用数据共享的机制,任何时候同一Provider只会创建一次,是由系统进行初始化和管理的。本文中将通过实现一个简单通讯录的插入、删除、查询操作来让你了解ContentProvider机制极其自定义过程。读过本系列(读取手机中通讯录)(sqlite数据库操作)的读者可以发现,本文中实现的应用以这两篇内容为基础的。虽然,本文的MyContentProvider使用sqlite数据库进行持久化存储操作,包装后以ContentProvider机制供各app调用。但是,为理解ContentProvider,你必须有这样两个概念:一、它是一种可以跨应用共享数据的机制,正如本文开头所说。二、底层的存储在实现你的ContentProvider的时候可以自定义,即可以为数据库、也可以为文件,持久化或非持久化存储的其他形式。

程序截图如下:



类AcMain.java,为主Activity,用来实现应用的主界面控件和流程,代码:

//AcMain.java

package jtapp.contentproviders;

import android.app.Activity;

import android.content.ContentValues;

import android.database.Cursor;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.TextView;

public class AcMain extends Activity {

private Button btInsertData = null;

private Button btViewData = null;

private Button btDelOne = null;

private Button btClearAll = null;

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

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

btInsertData = (Button) findViewById(R.id.Button02);

btInsertData.setOnClickListener(new ClickViewHandler());

btViewData = (Button) findViewById(R.id.Button03);

btViewData.setOnClickListener(new ClickViewHandler());

btDelOne = (Button) findViewById(R.id.Button04);

btDelOne.setOnClickListener(new ClickViewHandler());

btClearAll = (Button) findViewById(R.id.Button05);

btClearAll.setOnClickListener(new ClickViewHandler());

}

public class ClickViewHandler implements OnClickListener {

@Override

public void onClick(View v) {

if (v == btInsertData) {

InsertSomeRecords();

} else if (v == btViewData) {

ViewRecords();

} else if (v == btDelOne) {

DelOne();

} else if (v == btClearAll) {

DelAllPeople();

}

}

private void DelAllPeople() {

getContentResolver().delete(MyContacts.CONTENT_URI, null, null);

}

private void DelOne() {

int id;

Cursor c = getContentResolver().query(

MyContacts.CONTENT_URI, null,

null, null, MyContacts.NAME + " ASC");

if (c.moveToFirst()) {

int idxID = c.getColumnIndex(MyContacts._ID);

id = c.getInt(idxID);

getContentResolver().delete(MyContacts.CONTENT_URI,

MyContacts._ID + " = " + id, null);

}

}

private void ViewRecords() {

// Make the query

Cursor c = managedQuery(MyContacts.CONTENT_URI, null, null, null,

MyContacts._ID);

StringBuilder sbRecords = new StringBuilder("");

if (c.moveToFirst()) {

int idxID = c.getColumnIndex(MyContacts._ID);

int idxName = c.getColumnIndex(MyContacts.NAME);

int idxNumber = c.getColumnIndex(MyContacts.NUMBER1);

int idxEmail = c.getColumnIndex(MyContacts.EMAIL);

// Iterator the records

do {

sbRecords.append(c.getInt(idxID));

sbRecords.append(". ");

sbRecords.append(c.getString(idxName));

sbRecords.append(", ");

sbRecords.append(c.getString(idxNumber));

sbRecords.append(", ");

sbRecords.append(c.getString(idxEmail));

sbRecords.append("/n");

} while (c.moveToNext());

}

c.close();

// Refresh the content of TextView

((TextView)(findViewById(

R.id.TextView01))).setText(sbRecords);

}

private void InsertSomeRecords() {

ContentValues values = new ContentValues();

values.put(MyContacts.NAME, "朱元璋");

values.put(MyContacts.NUMBER1, "13965625585");

getContentResolver().insert(MyContacts.CONTENT_URI, values);

values.clear();

values.put(MyContacts.NAME, "玄烨");

values.put(MyContacts.EMAIL, "xueye1772@gmail.com");

getContentResolver().insert(MyContacts.CONTENT_URI, values);

}

}

}

复制代码

代码中通过getContentResolver()调用contentprovider的delete、insert等操作,由系统根据uri决定调用哪个provider。

query查询除了用getContentResolver().query以外,还可以用activity.managedQuery调用,后者的Cursor的生命周期是由activity来自动管理,本文中的query就是属于这种情况。

主界面ui定义,main.xml,代码:

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

android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent">

<TextView android:layout_width="fill_parent"

android:layout_height="wrap_content" android:text="@string/hello" />

<TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content"

android:layout_height="wrap_content">

<Button android:text="insert some records" android:id="@+id/Button02"

android:height="30px" android:layout_width="wrap_content"

android:layout_height="wrap_content" />

</TableRow>

<TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content"

android:layout_height="wrap_content">

<Button android:text="delete one" android:id="@+id/Button04"

android:height="30px" android:layout_width="wrap_content"

android:layout_height="wrap_content" />

<Button android:text="clear all" android:id="@+id/Button05"

android:height="30px" android:layout_width="wrap_content"

android:layout_height="wrap_content" />

</TableRow>

<Button android:text="view records" android:id="@+id/Button03"

android:height="30px" android:layout_width="wrap_content"

android:layout_height="wrap_content" android:layout_gravity="center" />

<TextView android:text="..." android:id="@+id/TextView01"

android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>

复制代码

MyContentProvider.java,代码:

package jtapp.contentproviders;

import android.content.ContentProvider;

import android.content.ContentUris;

import android.content.ContentValues;

import android.content.Context;

import android.database.Cursor;

import android.database.SQLException;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteQueryBuilder;

import android.database.sqlite.SQLiteStatement;

import android.net.Uri;

import android.text.TextUtils;

import android.util.Log;

public class MyContactsProvider extends ContentProvider {

private static final String TAG = "MyContactsProvider";

private static SQLiteDatabase mDB;

private static void createTablesIfNotExists() {

mDB.execSQL("CREATE TABLE IF NOT EXISTS "

+ MyContacts.TB_NAME + " ("

+ MyContacts._ID + " INTEGER PRIMARY KEY,"

+ MyContacts.NAME + " VARCHAR,"

+ MyContacts.NUMBER1 + " VARCHAR,"

+ MyContacts.EMAIL + " VARCHAR)");

}

@Override

public int delete(Uri uri, String selection, String[] selectionArgs) {

int count;

switch (MyContacts.uriMatcher.match(uri)) {

case MyContacts.CONTACTS:

count = mDB.delete(MyContacts.TB_NAME,

selection, selectionArgs);

break;

case MyContacts.CONTACT_ID:

String contactID = uri.getPathSegments().get(1);

count = mDB.delete(MyContacts.TB_NAME,

MyContacts._ID + "=" + contactID, selectionArgs);

break;

default: throw new IllegalArgumentException(

"Unsupported URI: " + uri);

}

return count;

}

@Override

public String getType(Uri uri) {

switch (MyContacts.uriMatcher.match(uri)) {

case MyContacts.CONTACTS:

return "vnd.android.cursor.dir/vnd.jtapp.contacts";

case MyContacts.CONTACT_ID:

return "vnd.android.cursor.item/vnd.ambow.contacts";

default:

throw new IllegalArgumentException("Unsupported URI: " + uri);

}

}

@Override

public Uri insert(Uri uri, ContentValues contentValues) {

long rowId = mDB.insert(MyContacts.TB_NAME, null, contentValues);

if (rowId > 0) {

Uri noteUri =

ContentUris.withAppendedId(MyContacts.CONTENT_URI,rowId);

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

Log.d(TAG+"insert",noteUri.toString());

return noteUri;

} else {

throw new SQLException("Failed to insert row into " + uri);

}

}

@Override

public boolean onCreate() {

if (mDB == null) {

mDB = this.getContext().openOrCreateDatabase(MyContacts.TB_NAME,

Context.MODE_PRIVATE, null);

createTablesIfNotExists();

}

return mDB != null;

}

@Override

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

String[] selectionArgs, String sortOrder) {

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

qb.setTables(MyContacts.TB_NAME);

switch (MyContacts.uriMatcher.match(uri)) {

case MyContacts.CONTACT_ID:

qb.appendWhere(

MyContacts._ID + "=" + uri.getPathSegments().get(1));

break;

}

String orderBy;

if (TextUtils.isEmpty(sortOrder)) {

orderBy = MyContacts._ID;

} else {

orderBy = sortOrder;

}

Cursor c = qb.query(mDB, projection, selection,

selectionArgs,null, null,orderBy);

return c;

}

@Override

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

String[] selectionArgs) {

Log.d(TAG+"update",contentValues.toString());

Log.d(TAG+"update",uri.toString());

int count;

switch (MyContacts.uriMatcher.match(uri)) {

case MyContacts.CONTACTS:

Log.d(TAG+"update",MyContacts.CONTACTS+"");

count = mDB.update(

MyContacts.TB_NAME, contentValues,

selection, selectionArgs);

break;

case MyContacts.CONTACT_ID:

String contactID = uri.getPathSegments().get(1);

Log.d(TAG+"update",contactID+"");

count = mDB.update(MyContacts.TB_NAME,contentValues,

MyContacts._ID + "=" + contactID,

selectionArgs);

break;

default: throw new IllegalArgumentException(

"Unsupported URI: " + uri);

}

return count;

}

}

复制代码
MyContentProvider扩展了android.content.ContentProvider类,数据层的操作就在该类中完成。sqlite、文件形式、内存对象,持久化或者非持久化数据存储都可以包装在此类中,本文中使用了sqlite数据库进行持久化存储。

getContext().getContentResolver().notifyChange可以通知观察者数据发生改变,这是处理多应用调用时数据同步的关键,本文并没有完整的展现。自定义的MyContentProvider.java中还实现了update方法,在AcMain中没有调用到,你可尝试一下如何实现。

与MyContentProvider有关的表mycontacts相对应类MyContacts.java,其中定义了唯一资源标示URI,表结构字段名等。任何contentprovider的调用都是通过系统来进行,因此,URI起到了定位资源和特定provider类的作用。

//MyContacts.java

package jtapp.contentproviders;

import android.content.UriMatcher;

import android.net.Uri;

import android.provider.BaseColumns;

public class MyContacts implements BaseColumns {

public MyContacts(){

}

public static final String AUTHORITY =

"jtapp.contentproviders.contacts";

public static final String TB_NAME = "mycontacts";

public static final Uri CONTENT_URI = Uri.parse(

"content://" + AUTHORITY + "/" + TB_NAME);

public static final int CONTACTS = 1;

public static final int CONTACT_ID = 2;

public static final UriMatcher uriMatcher;

static{

uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

uriMatcher.addURI(AUTHORITY,"mycontacts",CONTACTS);

uriMatcher.addURI(AUTHORITY,"mycontacts/#",CONTACT_ID);

}

public static final String _ID = "id";

public static final String NAME = "name";

public static final String NUMBER1 = "number1";

public static final String EMAIL = "email";

}

复制代码

应用配置文件AndroidManifest.xml 代码:

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

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

package="jtapp.contentproviders" android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".AcMain" android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

<provider android:authorities="jtapp.contentproviders.contacts"

android:name="MyContactsProvider"></provider>

</application>

</manifest>

复制代码
主要是里边插入了provider标签,向系统声明了自定义Provider的实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: