首页 > 代码库 > android开发步步为营之34:四大组件之ContentProvider

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

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=http://www.mamicode.com/"@drawable/icon" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentLeft="true">
    <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来实现了。

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