首页 > 代码库 > ContentProvider组件

ContentProvider组件

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">一、ContentProvider简介</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">	</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255); color: red;">统一了数据访问方式</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">。</span>

当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:

public class PersonContentProvider extends ContentProvider{
   public boolean onCreate()
   public Uri insert(Uri uri, ContentValues values)
   public int delete(Uri uri, String selection, String[] selectionArgs)
   public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
   public String getType(Uri uri)}

第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider ContentProvider采用了authorities(主机名/域名对它进行唯一标识,你可以把ContentProvider看作是一个网站想想,网站也是提供数据者authorities就是他的域名:

<manifest .... >
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <provider android:name=".PersonContentProvider" android:authorities="cncsdn.provider.personprovider"/>
    </application>
</manifest>
二、ContentProvider类主要方法的作用

public booleanonCreate()

该方法在ContentProvider创建后就会被调用,Android开机后, ContentProvider在其它应用第一次访问它时才会被创建。

public Uri insert(Uri uri,ContentValuesvalues)

该方法用于供外部应用往ContentProvider添加数据。

public intdelete(Uri uri,String selection, String[] selectionArgs)

该方法用于供外部应用从ContentProvider删除数据。

public intupdate(Uri uri,ContentValuesvalues, String selection, String[] selectionArgs)

该方法用于供外部应用更新ContentProvider中的数据。

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

该方法用于供外部应用从ContentProvider中获取数据。

public String getType(Uriuri)

该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。

三、使用ContentResolver操作ContentProvider中的数据

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

public Uri insert(Uri uri,ContentValuesvalues)

该方法用于往ContentProvider添加数据。

public intdelete(Uri uri,String selection, String[] selectionArgs)

该方法用于从ContentProvider删除数据。

public intupdate(Uri uri,ContentValuesvalues, String selection, String[] selectionArgs)

该方法用于更新ContentProvider中的数据。

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

该方法用于从ContentProvider中获取数据。

这些方法的第一个参数为Uri,代表要操作的是哪个ContentProvider和对其中的什么数据进行操作,假设给定的是:Uri.parse(“content://cn.csdn.provider.personprovider/person/10”),那么将会对主机名为cn.itcast.provider.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。

四、监听ContentProvider中数据的变化

如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化,可以在ContentProvider 发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,例子如下:

public class PersonContentProviderextends ContentProvider{
publicUri insert(Uri uri, ContentValuesvalues) {
  db.insert("person","personid",values);
  getContext().getContentResolver().notifyChange(uri,null);
}
}

如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:

getContentResolver().registerContentObserver(Uri.parse("content://cn.itcast.providers.personprovider/person"),
          true,new PersonObserver(newHandler()));
public class PersonObserverextends ContentObserver{
  publicPersonObserver(Handlerhandler) {
  super(handler);
   }
  publicvoid onChange(booleanselfChange){
      //此处可以进行相应的业务处理
  }
}

五、ContentProvider的测试

1、首先创建创建ContentProvider类

以下是BaseDaoImp.java封装的增删改查

package www.gxw.com.sqlit.dao.impl;

import www.gxw.com.sqlit.dao.BaseDao;
import www.gxw.com.sqlit.dataBase.DataBaseHelper;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class BaseDaoImpl implements BaseDao{
	// 依赖DataBaseHelper的对象
		private DataBaseHelper dataBaseHelper;

		public BaseDaoImpl(DataBaseHelper dataBaseHelper) {
			// TODO Auto-generated constructor stub
			this.dataBaseHelper = dataBaseHelper;
		}

		@Override
		public long insert(String table, String nullColumnHack, ContentValues values) {
			SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
			long insert = db.insert(table, nullColumnHack, values);
			db.close();
			return insert;
		}

		@Override
		public Cursor query(String table, String columns[], String selection,
				String[] selectionArgs, String groupBy, String having,
				String orderBy) {
			SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
			return db.query(table, columns, selection, selectionArgs, groupBy,
					having, orderBy);

		}

		@Override
		public Cursor query(String table, String columns[], String selection,
				String[] selectionArgs, String groupBy, String having,
				String orderBy, String limit) {
			SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
			return db.query(table, columns, selection, selectionArgs, groupBy,
					having, orderBy, limit);
		}

		@Override
		public int update(String table, ContentValues values, String whereClause,
				String whereArgs[]) {
			SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
			int i = db.update(table, values, whereClause, whereArgs);
			db.close();
			return i;
		}

		@Override
		public int delete(String table, String whereClause, String[] whereArgs) {
			SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
			int i = db.delete(table, whereClause, whereArgs);
			db.close();
			return i;
		}

}


以下是UserContentProvider.java的实现代码

package www.gxw.com.sqlit.provider;

import www.gxw.com.sqlit.dataBase.DataBaseHelper;
import android.R.integer;
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;

public class UserContentProivder extends ContentProvider {

	private static final String AUTHORITIES = "www.gxw.com.sqlit.provider.usercontentproivder";

	private DataBaseHelper dataBaseHelper;

	private static UriMatcher uriMatcher;

	private static final int USERSCODE = 1;
	private static final int USERCODE = 2;
	private String USERS_DIR = "vnd.android.cursor.dir/";
	private String USERS_ITEM = "vnd.android.cursor.item/";

	static {
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		// www.gxw.com.sqlit.provider.usercontentproivder/user代表用户信息操作
		uriMatcher.addURI(AUTHORITIES, "users", USERSCODE);
		// www.gxw.com.sqlit.provider.usercontentproivder/user/1代表查询用户信息
		uriMatcher.addURI(AUTHORITIES, "users/#", USERCODE);

	}

	@Override
	public boolean onCreate() {
		// TODO Auto-generated method stub
		this.dataBaseHelper = new DataBaseHelper(getContext(), 1);
		return false;
	}

	

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
		Cursor c = null;
		switch (uriMatcher.match(uri)) {
		case USERCODE:
			long id =  ContentUris.parseId(uri);
			c = db.query("users", projection, "userid",
					new String[] { "" + id }, null, null, sortOrder);
			break;
		case USERSCODE:
			c = db.query("users", projection, selection, selectionArgs, null,
					null, sortOrder);
			break;
		default:
			throw new IllegalArgumentException("Unkonw uri" + uri);
		}

		return c;
	}
	
	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		/**
		 * 操作的条目是多个还是一个
		 */
		String value = http://www.mamicode.com/null;> 2、添加Instrumentation

3、添加Application Nodes

4、创建其他应用other

添加Instrumentation以及Application Nodes权限

以下是MainActivity.java实现代码:

package www.gxw.com.other2;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity implements OnScrollListener {

	private boolean flag = false;
	private boolean isLastRow = false;

	private ListView lv_users;
	private TextView tv_tip;

	private SimpleCursorAdapter adapter;
	private ContentResolver contentResolver;

	private static final String URL = "content://www.gxw.com.sqlit.provider.usercontentproivder/users";

	private static final int INSERT = 1;

	private Handler handler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			super.handleMessage(msg);
			switch (msg.what) {
			case INSERT:
				tv_tip.setVisibility(View.VISIBLE);
				flag = true;
				tv_tip.setText("有新信息");
				break;

			default:
				break;
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tv_tip = (TextView) findViewById(R.id.tv_tip);
		tv_tip.setVisibility(View.GONE);// 不占用位置,彻底隐藏

		lv_users = (ListView) findViewById(R.id.lv_users);
		// 获取解析内容
		contentResolver = getContentResolver();
		initData();

		lv_users.setOnScrollListener(this);

		// 注册监听器Observer
		/**
		 * 如果为true 模糊匹配
		 */
		getContentResolver().registerContentObserver(Uri.parse(URL), true,
				new UserContentObserver(handler));
	}

	private void initData() {
		Cursor c = contentResolver.query(Uri.parse(URL), new String[] {
				"userid as _id", "username", "userphone" }, null, null,
				"userid desc");
		// 控制层
		adapter = new SimpleCursorAdapter(this, R.layout.list_item_user, c,
				new String[] { "username", "userphone" }, new int[] {
						R.id.tv_name, R.id.tv_phone },
				CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

		lv_users.setAdapter(adapter);
	}
	//
	class UserContentObserver extends ContentObserver {

		private Handler handler;

		public UserContentObserver(Handler handler) {
			super(handler);
			// TODO Auto-generated constructor stub
			this.handler = handler;
		}

		@Override
		public void onChange(boolean selfChange) {
			// TODO Auto-generated method stub
			super.onChange(selfChange);
			System.out.println("有新信息插入");
			/*
			 * System.out.println("iiiiiiii"); Toast.makeText(MainActivity.this,
			 * "fasdf", Toast.LENGTH_LONG) .show();
			 */

			handler.sendEmptyMessage(INSERT);
			tv_tip.setText("有新信息");
		}

	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		// TODO Auto-generated method stub
	/*	Toast.makeText(this, "========" + scrollState, Toast.LENGTH_LONG)
				.show();*/
		// 有新消息 更新的时候去加载数据
		if (flag && scrollState == OnScrollListener.SCROLL_STATE_FLING) {
			initData();
			flag = false;
	 		tv_tip.setVisibility(View.GONE);
		}

		if (isLastRow && scrollState == OnScrollListener.SCROLL_STATE_FLING) {
			// 去加载数据
		}
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		// TODO Auto-generated method stub
	/*	Toast.makeText(
				this,
				firstVisibleItem + "========" + visibleItemCount + "========="
						+ totalItemCount, Toast.LENGTH_LONG).show();*/

		if ((firstVisibleItem + visibleItemCount) >= totalItemCount
				&& totalItemCount > 0) {
			// 发送请求处理
			isLastRow = true;
		}
	}
}

activity_main.xml页面设计如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${packageName}.${activityClass}" >

    <TextView 
        android:id="@+id/tv_tip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:gravity="center"
        android:text="@string/tv_tip"/>
    
    <ListView
        android:id="@+id/lv_users"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/tv_tip"
        android:divider="#FF0000"
        android:dividerHeight="1dp"
        >
    </ListView>

</RelativeLayout>

list_item_user.xml页面布局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="用户名:" />

        <TextView
            android:id="@+id/tv_pass"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="密码:" />

        <TextView
            android:id="@+id/tv_phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="电话:" />
    </LinearLayout>

</RelativeLayout>

最后实现结果: