<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 = null;
switch (uriMatcher.match(uri)) {
case USERSCODE:
value = USERS_DIR;
break;
case USERCODE:
value = USERS_ITEM;
break;
}
return value;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
if (uriMatcher.match(uri) != USERSCODE) {
throw new IllegalArgumentException("Unkonw uri" + uri);
}
SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
long rowId = db.insert("users", "username", values);
//db.close();
//注册监听 通知所有注册在uri上的监听者
getContext().getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(uri, rowId);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
int rows = -1;
switch (uriMatcher.match(uri)) {
case USERCODE:
long id = ContentUris.parseId(uri);
rows = db.delete("users", "userid=?", new String[] { "" + id });
db.close();
break;
case USERSCODE:
rows = db.delete("users", selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unkonw uri" + uri);
}
return rows;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
int rows = -1;
switch (uriMatcher.match(uri)) {
case USERCODE:
long id = ContentUris.parseId(uri);
rows = db.update("users", values, "userid=?",
new String[] { "" + id });
db.close();
break;
case USERSCODE:
rows = db.update("users", values, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unkonw uri" + uri);
}
return rows;
}
}
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>
最后实现结果: