首页 > 代码库 > 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、添加Instrumentation3、添加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>
最后实现结果: