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

android开发步步为营之34:四大组件之ContentProvider

2014-09-24 12:00 429 查看
ContentProvider,从字面意义上理解,内容提供者,这个类目的就是一个桥梁的作用,让一个应用的数据(SQLiteDatabase, SharedPreferences,Xml,Txt等数据),通过ContentProvider可以让其他的应用访问。

理论知识

(一)、ContentProvider简介

当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。

(二)、Uri类简介

Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:

1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。

2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。

3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:

a、要操作contact表中id为10的记录,可以构建这样的路径:/contact/10

b、要操作contact表中id为10的记录的name字段, contact/10/name

c、要操作contact表中的所有记录,可以构建这样的路径:/contact

要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:

要操作xml文件中contact节点下的name节点,可以构建这样的路径:/contact/name

如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:

Uri uri = Uri.parse("content://com.figo.helloworld.MyContentProvider/contacter ")

(三)、UriMatcher、ContentUris和ContentResolver简介

因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。

UriMatcher:用于匹配Uri,它的用法如下:

1.首先把你需要匹配Uri路径全部给注册上,如下:

//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。

UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

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

uriMatcher.addURI(“content://com.figo.helloworld.MyContentProvider/contacter”, “contacter”, 1);//添加需要匹配uri,如果匹配就会返回匹配码

//如果match()方法匹配 content://com.figo.helloworld.MyContentProvider/contacter/230路径,返回匹配码为2

uriMatcher.addURI(“content://com.figo.helloworld.MyContentProvider”, “contacter /#”, 2);//#号为通配符

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

ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:

a、withAppendedId(uri, id)用于为路径加上ID部分

b、parseId(uri)方法用于从路径中获取ID部分

ContentResolver:当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,来操作数据。

(四)、ContentProvider需要在AndroidManifest.xml中的注册

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

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

package="com.figo.helloworld" android:versionCode="1" android:versionName="1.0">

<uses-sdk android:minSdkVersion="7" />

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

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

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

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

<provider android:name="com.figo.helloworld.MyContentProvider"

android:authorities="com.figo.helloworld.MyContentProvider" >

</provider>

<activity android:name=".ContentProviderActivity">

<intent-filter>

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

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

</intent-filter>

</activity>

</application>

</manifest>

实践操作

这个实例里面,在helloworld应用里面,我们创建一个名为联系人contacter的sqlitedatabase数据库,里面有一张表联系人contacter,包含字段联系人contacterid编号,name姓名,age年龄3个字段。然后通过contentprovider实现对sqlitedatabase数据的增删改查操作,同时使用gridview将数据展现出来,然后在另外一个应用里面Sudoku里面通过helloworld提供的contentprovider实现对helloworld应用contacter数据库的操作,从而实现数据的共享。

Helloworld应用

第一步、新建页面contentproviderview.xml,friendview.xml

contentproviderview.xml

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

<RelativeLayout

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

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent">

<TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:text="@string/contentprovider"></TextView>

<Button android:id="@+id/btnadd" android:layout_width="wrap_content" android:text="@string/add" android:layout_height="wrap_content" android:layout_below="@+id/textView1" android:layout_alignParentLeft="true" android:layout_marginTop="15dp"></Button>

<Button android:id="@+id/btndelete" android:layout_width="wrap_content" android:text="@string/delete" android:layout_height="wrap_content" android:layout_alignTop="@+id/btnadd" android:layout_toRightOf="@+id/btnadd" android:layout_marginLeft="30dp"></Button>

<Button android:id="@+id/btnupdate" android:layout_width="wrap_content" android:text="@string/update" android:layout_height="wrap_content" android:layout_alignTop="@+id/btndelete" android:layout_alignRight="@+id/textView1"></Button>

<Button android:id="@+id/btnquery" android:layout_width="wrap_content" android:text="@string/query" android:layout_height="wrap_content" android:layout_alignTop="@+id/btnupdate" android:layout_toRightOf="@+id/btnupdate" android:layout_marginLeft="24dp"></Button>

<LinearLayout android:layout_below="@+id/btnadd" android:layout_height="fill_parent" android:layout_width="fill_parent" >

<ScrollView android:id="@+id/scrollView1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#f66" android:layout_alignParentLeft="true" android:layout_marginTop="40dp" android:layout_alignParentRight="true">

<LinearLayout android:layout_height="fill_parent" android:layout_width="fill_parent" >

<GridView android:id="@+id/gvContentProvider" android:columnWidth="100dp" android:layout_width="wrap_content" android:layout_height="300dp"></GridView>

</LinearLayout>

</ScrollView>

</LinearLayout>

</RelativeLayout>

friendview.xml

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

<RelativeLayout

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

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent">

<ImageView android:id="@+id/imgHead" android:layout_width="wrap_content" android:src="@drawable/icon" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentLeft="true"></ImageView>

<TextView android:id="@+id/tvAge" android:layout_width="wrap_content" android:text="年龄" android:layout_height="wrap_content" android:layout_alignTop="@+id/tvName" android:layout_alignParentRight="true" android:layout_marginRight="43dp"></TextView>

<TextView android:layout_width="wrap_content" android:text="编号" android:layout_height="wrap_content" android:layout_alignBottom="@+id/imgHead" android:layout_toRightOf="@+id/imgHead" android:layout_marginBottom="14dp" android:id="@+id/tvPersonId"></TextView>

<TextView android:id="@+id/tvName" android:layout_width="wrap_content" android:text="姓名" android:layout_height="wrap_content" android:layout_alignTop="@+id/tvPersonId" android:layout_centerHorizontal="true"></TextView>

</RelativeLayout>

第二步、新建SQLiteOpenHelper MySQLiteOpenHelper.java

/**

*

*/

package com.figo.helloworld;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteDatabase.CursorFactory;

import android.database.sqlite.SQLiteOpenHelper;

/**

* @author zhuzhifei

*

*/

public class MySQLiteOpenHelper extends SQLiteOpenHelper {

private static final String SQLITE_NAME = "contacter";

private static final int version = 1;

public MySQLiteOpenHelper(Context context, String name,

CursorFactory factory, int version) {

super(context, name, factory, version);

// TODO Auto-generated constructor stub

}

public MySQLiteOpenHelper(Context context) {

super(context, SQLITE_NAME, null, version);

}

/*

* (non-Javadoc)

*

* @see

* android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite

* .SQLiteDatabase)

*/

@Override

public void onCreate(SQLiteDatabase arg0) {

// 新建一张联系人contacter表,包含主键、名字、年龄字段

arg0.execSQL("CREATE TABLE contacter (contacterid integer primary key autoincrement,name varchar(20),age INTEGER)");

}

/*

* (non-Javadoc)

*

* @see

* android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite

* .SQLiteDatabase, int, int)

*/

@Override

public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

// TODO Auto-generated method stub

arg0.execSQL("DROP TABLE IF EXISTS contacter");

onCreate(arg0);

}

}

第三步、新建ContentProvider MyContentProvider.java

/**

*

*/

package com.figo.helloworld;

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;

/**

* @author zhuzhifei

*

*/

public class MyContentProvider extends ContentProvider {

private MySQLiteOpenHelper mySQLiteOpenHelper;

private final static int CONTACTER = 1;

private final static int CONTACTERS = 2;

private final static String AUTHORITY = "com.figo.helloworld.MyContentProvider";

private static final UriMatcher pMatcher = new UriMatcher(

UriMatcher.NO_MATCH);

static {

pMatcher.addURI(AUTHORITY, "contacter", CONTACTERS);

pMatcher.addURI(AUTHORITY, "contacter/#", CONTACTER);

}

/*

* (non-Javadoc)

*

* @see android.content.ContentProvider#delete(android.net.Uri,

* java.lang.String, java.lang.String[])

*/

@Override

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

// TODO Auto-generated method stub

SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();

int count = 0;

switch (pMatcher.match(uri)) {

case CONTACTERS:

count = db.delete("contacter", selection, selectionArgs);

break;

case CONTACTER:

long sid = ContentUris.parseId(uri);

String where = TextUtils.isEmpty(selection) ? "contacterid=?"

: selection + "and contacterid=?";

String[] params = new String[] { String.valueOf(sid) };

if (!TextUtils.isEmpty(selection) && selectionArgs != null) {

params = new String[selectionArgs.length + 1];

for (int i = 0; i < selectionArgs.length; i++) {

params[i] = selectionArgs[i];

}

params[selectionArgs.length] = String.valueOf(sid);

}

count = db.delete("contacter", where, params);

break;

default:

throw new IllegalArgumentException("Unknow Uri:" + uri);

}

return count;

}

/*

* (non-Javadoc)

*

* @see android.content.ContentProvider#getType(android.net.Uri)

*/

@Override

public String getType(Uri uri) {

// TODO Auto-generated method stub

switch (pMatcher.match(uri)) {

case CONTACTERS:

return "vnd.android.cursor.dir/MyContentProvider.contacter";

case CONTACTER:

return "vnd.android.cursor.item/MyContentProvider.contacter";

default:

throw new IllegalArgumentException("Unknow Uri:" + uri);

}

}

/*

* (non-Javadoc)

*

* @see android.content.ContentProvider#insert(android.net.Uri,

* android.content.ContentValues)

*/

@Override

public Uri insert(Uri uri, ContentValues values) {

// TODO Auto-generated method stub

SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();

long pid = 0;

switch (pMatcher.match(uri)) {

case CONTACTERS:

pid = db.insert("contacter", "name", values);

return ContentUris.withAppendedId(uri, pid);

case CONTACTER:

pid = db.insert("contacter", "name", values);

String path = uri.toString();

return Uri

.parse(path.substring(0, path.lastIndexOf('/') + 1) + pid);

default:

throw new IllegalArgumentException("Unknow Uri:" + uri);

}

}

/*

* (non-Javadoc)

*

* @see android.content.ContentProvider#onCreate()

*/

@Override

public boolean onCreate() {

// TODO Auto-generated method stub

mySQLiteOpenHelper = new MySQLiteOpenHelper(this.getContext());

return true;

}

/*

* (non-Javadoc)

*

* @see android.content.ContentProvider#query(android.net.Uri,

* java.lang.String[], java.lang.String, java.lang.String[],

* java.lang.String)

*/

@Override

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

String[] selectionArgs, String sortOrder) {

// TODO Auto-generated method stub

SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();

switch (pMatcher.match(uri)) {

case CONTACTERS:

return db.query("contacter", projection, selection, selectionArgs,

null, null, sortOrder);

case CONTACTER:

long pid = ContentUris.parseId(uri);

String where = TextUtils.isEmpty(selection) ? "contacterid=?"

: selection + "and contacterid=?";

String[] params = new String[] { String.valueOf(pid) };

if (!TextUtils.isEmpty(selection) && selectionArgs != null) {

params = new String[selectionArgs.length + 1];

for (int i = 0; i < selectionArgs.length; i++) {

params[i] = selectionArgs[i];

}

}

return db.query("contacter", projection, where, params, null, null,

sortOrder);

default:

throw new IllegalArgumentException("Unknow Uri:" + uri);

}

}

/*

* (non-Javadoc)

*

* @see android.content.ContentProvider#update(android.net.Uri,

* android.content.ContentValues, java.lang.String, java.lang.String[])

*/

@Override

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

String[] selectionArgs) {

// TODO Auto-generated method stub

SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();

int count = 0;

switch (pMatcher.match(uri)) {

case CONTACTERS:

count = db.update("contacter", values, selection, selectionArgs);

break;

case CONTACTER:

long sid = ContentUris.parseId(uri);

String where = TextUtils.isEmpty(selection) ? "contacterid=?"

: selection + "and contacterid=?";

String[] params = new String[] { String.valueOf(sid) };

if (!TextUtils.isEmpty(selection) && selectionArgs != null) {

params = new String[selectionArgs.length + 1];

for (int i = 0; i < selectionArgs.length; i++) {

params[i] = selectionArgs[i];

}

params[selectionArgs.length] = String.valueOf(sid);

}

count = db.delete("contacter", where, params);

break;

default:

throw new IllegalArgumentException("Unknow Uri:" + uri);

}

return count;

}

}

第四步、新建Activity ContentProviderActivity.java

/**

*

*/

package com.figo.helloworld;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import android.app.Activity;

import android.content.ContentResolver;

import android.content.ContentUris;

import android.content.ContentValues;

import android.database.Cursor;

import android.net.Uri;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.AdapterView;

import android.widget.AdapterView.OnItemClickListener;

import android.widget.Button;

import android.widget.GridView;

import android.widget.SimpleAdapter;

/**

* @author zhuzhifei

*

*/

public class ContentProviderActivity extends Activity implements

OnClickListener {

private Button btnAdd;

private Button btnDelete;

private Button btnUpdate;

private Button btnQuery;

private ContentResolver resolver;

private int count;//行数

private String contacterid;//选中的

private List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

//Uri uri=Uri.parse("content://com.figo.helloworld.MyContentProvider/contacter/#");

Uri uri=Uri.parse("content://com.figo.helloworld.MyContentProvider/contacter");

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

this.setContentView(R.layout.contentproviderview);

resolver=this.getContentResolver();

btnAdd=(Button)findViewById(R.id.btnadd);

btnDelete=(Button)findViewById(R.id.btndelete);

btnUpdate=(Button)findViewById(R.id.btnupdate);

btnQuery=(Button)findViewById(R.id.btnquery);

btnAdd.setOnClickListener(this);

btnDelete.setOnClickListener(this);

btnUpdate.setOnClickListener(this);

btnQuery.setOnClickListener(this);

}

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

switch (v.getId()) {

case R.id.btnadd://增

count=count+1;

ContentValues cvadd=new ContentValues();

cvadd.put("name", "朋友"+count);

cvadd.put("age", "32");

Uri uriadd=resolver.insert(uri, cvadd);

long countnew=ContentUris.parseId(uriadd);

count=Integer.parseInt(String.valueOf(countnew));

query();

break;

case R.id.btndelete://删

String[] deleteparas=new String[1];

deleteparas[0]=String.valueOf(contacterid);

resolver.delete(uri, "contacterid=?", deleteparas);

query();

break;

case R.id.btnupdate://改

String[] updateparas=new String[1];

updateparas[0]=String.valueOf(contacterid);

ContentValues cvupdate=new ContentValues();

cvupdate.put("name", "朋友啊朋友"+contacterid);

cvupdate.put("age", "30");

resolver.update(uri,cvupdate, "contacterid=?", updateparas);

query();

break;

case R.id.btnquery://查

query();

count=list.size();

break;

default:

break;

}

}

//查询方法

private void query()

{

//Cursor cursor=resolver.query(uri, projection, selection, selectionArgs, "contacterid desc");

list.clear();//先清理

Cursor cursor=resolver.query(uri, new String[]{"contacterid","name","age"}, null, null, "contacterid desc");

while(cursor.moveToNext())

{

Map<String, Object> map = new HashMap<String, Object>();

map.put("contacterid", cursor.getString(0));

map.put("img", R.drawable.icon);

map.put("name", cursor.getString(1));

map.put("age", cursor.getString(2));

list.add(map);

}

// 生成适配器

SimpleAdapter adapter = new SimpleAdapter(this, list,

R.layout.friendview, new String[] { "img","contacterid", "name", "age" },

new int[] { R.id.imgHead,R.id.tvPersonId, R.id.tvName, R.id.tvAge });

GridView gridView = (GridView) findViewById(R.id.gvContentProvider);

gridView.setAdapter(adapter);

gridView.setColumnWidth(200);

// 添加点击行事件

gridView.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView parent, View view, int position, long id) {

// 在本例中arg2=arg3

Map<String, Object> item = (Map<String, Object>) parent.getItemAtPosition(position);

// 显示所选Item的ItemText

setTitle(item.get("name").toString());

contacterid=item.get("contacterid").toString();

}

});

}

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

}

@Override

protected void onPause() {

// TODO Auto-generated method stub

super.onPause();

}

@Override

protected void onRestart() {

// TODO Auto-generated method stub

super.onRestart();

}

@Override

protected void onResume() {

// TODO Auto-generated method stub

super.onResume();

}

@Override

protected void onStart() {

// TODO Auto-generated method stub

super.onStart();

}

@Override

protected void onStop() {

// TODO Auto-generated method stub

super.onStop();

}

}

第五步、AndroidManifest.xml注册之前创建的MyContentProvider.java和ContentProviderActivity.java

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

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

package="com.figo.helloworld" android:versionCode="1" android:versionName="1.0">

<uses-sdk android:minSdkVersion="7" />

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

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

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

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

<provider android:name="com.figo.helloworld.MyContentProvider"

android:authorities="com.figo.helloworld.MyContentProvider" >

</provider>

<activity android:name=".ContentProviderActivity">

<intent-filter>

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

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

</intent-filter>

</activity>

</application>

</manifest>

第六步、运行效果



在手机或者模拟器里面安装了helloworld应用之后,Sudoku应用中,同理将helloworld的ContentProviderActivity.java、contentproviderview.xml、friendview.xml拷过来,通过resolver=this.getContentResolver();获取到helloworld暴露出来的com.figo.helloworld.MyContentProvider就发现直接可以操作helloworld里面的数据了。所以一个应用需要向另外一个应用暴露数据的时候,我们就可以方便的使用ContentProvider来实现了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: