ContentProvider 内容提供者,是Android四大组件之一。
一、简述
可以理解为一个特殊的存储数据的类型,它提供了一套标准的接口来获取和操作数据。可以把数据封装到ContentProvider
中,从而是这些数据可以被其他的应用程序所共享。搭建起了所有应用程序之间数据交换的桥梁!
1.
内容提供者可以将应用中的数据对外进行共享
2.内容提供者将数据的访问方式统一,不必针对不同数据类型采取不同的访问策略
3.内容提供者将数据封装,只暴露出我们希望提供给其他程序的数据
4.内容提供者中数据更改可被监听
二、创建内容提供者
定义类继承ContentProvider,根据需要重写内部方法
在清单文件的<application>节点下进行配置,<provider>标签中需要指定name和authorities属性
name为类名,包名从程序Package开始,以“.”开始
authorities:是访问Provider时的路径,要唯一
URI代表要操作的数据,由scheme、authorites、path三部分组成
content://com.bruce.contentprovider.demo/student
scheme:固定为content,代表访问内容提供者
authorites:<provider>节点中的authorites属性
path:程序定义的路径,可根据业务逻辑定义
--------------------------------------------------------------------------------------------------
<provider
android:name="com.bruce.contentprovider.demo.MyContentProvider"
android:authorities="com.bruce.contentprovider.demo"
></provider>
--------------------------------------------------------------------------------------------------
getType方法中:
? 如果返回数据是单条数据:vnd.android.cursor.item
? 如果返回数据是多条数据:vnd.android.cursor.dir
三、完成CRUD方法
? 当程序调用CRUD方法时会传入Uri, 我们通过Uri判断调用者要操作的数据,可以使用工具类UriMatcher来判断Uri,addURI方法可以添加Uri,match方法可以匹配一个Uri判断其类型;根据业务逻辑操作数据。
1.onCreate()
:初始化该ContentProvider
2.query(Uri,String[],String,Sring[],String)
:通过Uri进行查询,返回Uri
3.intert(Uri,ContentValues):将数据插入到Uri所指定的位置
4.update(Uri,ContentValues,String,String
[]):更新uri指定位置的数据
5.delete(Uri,String,String[]):删除uri指定位置的数据
6.getType(Uri):返回数据的类型
四、建立contentprovider工程,添加单元测试(http://www.cnblogs.com/kingshow123/p/sqlitecreate.html 中有介绍)
五、创建DbOpenHelper类
package com.bruce.contentprovider.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; public class DbOpenHelper extends SQLiteOpenHelper { private static String name = "mycont.db"; private static int version = 1; public DbOpenHelper(Context context) { super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase db) { String sql = "create table student( id integer primary key autoincrement,name varchar(64),address varchar(64))"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) { // TODO Auto-generated method stub } }
六、创建MyContentProvider类
package com.bruce.contentprovider.demo; import com.bruce.contentprovider.db.DbOpenHelper; 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 MyContentProvider extends ContentProvider { private DbOpenHelper helper; private final static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); private final static int STUDENT = 0; private final static int STUDENTS = 1; static{ matcher.addURI("com.bruce.contentprovider.demo", "student/#", STUDENT); //单条记录 matcher.addURI("com.bruce.contentprovider.demo", "student", STUDENTS); //多条记录 } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = -1; SQLiteDatabase database = helper.getWritableDatabase(); switch (matcher.match(uri)) { case STUDENT: long id = ContentUris.parseId(uri); selection = (selection == null ? " id = " + id : " id = " + id + " and " + selection); count = database.delete("student", selection, selectionArgs); break; case STUDENTS: count = database.delete("student", selection, selectionArgs); break; default: throw new IllegalArgumentException("No match uri:" + uri); } return count; } @Override public String getType(Uri uri) { switch (matcher.match(uri)) { case STUDENT: return "vnd.android.cursor.item/student"; case STUDENTS: return "vnd.android.cursor.dir/student"; default: throw new IllegalArgumentException("No match uri:" + uri); } } @Override public Uri insert(Uri uri, ContentValues values) { Uri resultUri = null; switch (matcher.match(uri)) { case STUDENTS: SQLiteDatabase database = helper.getWritableDatabase(); long id = database.insert("student", null,values); resultUri = ContentUris.withAppendedId(uri, id); break; default: throw new IllegalArgumentException("No match uri:" + uri); } return resultUri; } @Override public boolean onCreate() { helper = new DbOpenHelper(getContext()); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor cursor = null; switch (matcher.match(uri)) { case STUDENT: long id = ContentUris.parseId(uri); selection = selection == null ? " id = " + id : " id = " + id + " and " + selection; case STUDENTS: SQLiteDatabase database = helper.getWritableDatabase(); cursor = database.query("student", projection, selection, selectionArgs, null, null, sortOrder); break; default: throw new IllegalArgumentException("No match uri:" + uri); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { switch (matcher.match(uri)) { case STUDENT: long id = ContentUris.parseId(uri); selection = (selection == null ? " id = " + id : " id = " + id + " and " + selection); case STUDENTS: SQLiteDatabase database = helper.getWritableDatabase(); return database.update("student", values, selection, selectionArgs); //directly return the number of rows affected default: throw new IllegalArgumentException("No match uri:" + uri); } } }
七、创建MyTestProvider类
package com.bruce.contentprovider.test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.test.AndroidTestCase; import android.util.Log; public class MyTestProvider extends AndroidTestCase { private String TAG = "MyTestProvider"; public void insertStudent(){ ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student"); ContentValues values = new ContentValues(); values.put("name", "姚明"); values.put("address", "上海"); Uri reUri = resolver.insert(uri, values); Cursor cursor = resolver.query(reUri, null, null, null, null); if(cursor.moveToNext()){ int id = cursor.getInt(0); String name = cursor.getString(1); String address = cursor.getString(2); Log.i(TAG, "-->test insert id:" + id + ",name:" + name + ",address:" + address); } } public void deleteStudent(){ ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student/5"); //String selection = " name = ? "; //String[] selectionArgs = {"姚明"}; //int count = resolver.delete(uri, selection, selectionArgs); int count = resolver.delete(uri, null, null); Log.i(TAG, "-->test delete count=" + count); } public void updateStudent(){ ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student/1"); ContentValues values = new ContentValues(); values.put("name", "邹市明"); values.put("address","遵义"); //String selection = " name = ? "; //String[] selectionArgs = {"老毛"}; //int count = resolver.update(uri, values, selection, selectionArgs); int count = resolver.update(uri, values, null, null); Log.i(TAG, "-->test update count = " + count); } public void queryById(){ ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student/1"); Cursor cursor = resolver.query(uri, null, null, null, null); while(cursor.moveToNext()){ int id = cursor.getInt(0); String name = cursor.getString(1); String address = cursor.getString(2); Log.i(TAG, "--> test queryById id = " + id + ",name = " + name + ",address= " + address); } } public void queryByName(){ Map<String, String> map = new HashMap<String, String>(); ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student"); String selection = " name = ? "; String[] selectionArgs = {"姚明"}; Cursor cursor = resolver.query(uri, null, selection, selectionArgs, null); int count = cursor.getColumnCount(); while(cursor.moveToNext()){ for(int i=0; i<count; i++){ String cols_name = cursor.getColumnName(i); String cols_value = cursor.getString(cursor.getColumnIndex(cols_name)); map.put(cols_name, cols_value); } } Log.i(TAG, "-->test queryByName:" + map.toString()); } public void queryListStudent(){ List<Map<String, String>> list = new ArrayList<Map<String,String>>(); ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student"); Cursor cursor = resolver.query(uri, null, null, null, null); int count = cursor.getColumnCount(); while(cursor.moveToNext()){ Map<String, String> map = new HashMap<String, String>(); for(int i=0; i<count; i++){ String cols_name = cursor.getColumnName(i); String cols_value = cursor.getString(cursor.getColumnIndex(cols_name)); map.put(cols_name, cols_value); } list.add(map); } Log.i(TAG, "-->test queryListStudent:" + list.toString()); } public void testGetType(){ ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student/1"); Log.i(TAG, "-->testGetType plus id:" + resolver.getType(uri)); uri = Uri.parse("content://com.bruce.contentprovider.demo/student"); Log.i(TAG, "-->testGetType:" + resolver.getType(uri)); } }
八、监听内容提供者数据变化
? 在内容提供者中可以通知其他程序数据发生变化,通过Context的getContentResolver()方法获取ContentResolver,调用其notifyChange()方法发送数据修改通知;
? 在其他程序中可以通过ContentObserver监听数据变化
通过Context的getContentResolver()方法获取ContentResolver
调用其registerContentObserver()方法指定对某个Uri注册ContentObserver
自定义ContentObserver,重写onChange()方法获取数据
发送修改通知:
public Uri insert(Uri uri, ContentValues values) { Uri resultUri = null; switch (matcher.match(uri)) { case STUDENTS: SQLiteDatabase database = helper.getWritableDatabase(); long id = database.insert("student", null,values); // Notify registered observers that a row was updated. 注册 observer // @param observer The observer that originated the change, may be null // 产生改变的Observer. 此处为Provider带来的改变,传 null this.getContext().getContentResolver().notifyChange(uri, null);// 发送修改通知 //resultUri = Uri.parse("content://com.bruce.contentprovider.demo/student" + id); resultUri = ContentUris.withAppendedId(uri, id); break; default: throw new IllegalArgumentException("No match uri:" + uri); } return resultUri; }
也可以在其他应用中定义一个ContentObserver,监听Uri所对应的内容提供者的变化
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //定义一个ContentObserver ContentObserver observer = new ContentObserver(new Handler()) { /** * Returns true if this observer is interested in notifications for * changes made through the cursor the observer is registered with. */ // 是否传递自己的改变 @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } // 当被监听的内容发生了改变时,调用该方法 @Override public void onChange(boolean selfChange) { Log.i("MainActivity", "监听到了变化!!"); //打印最后插入的信息 ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student"); //select * from student order by id desc limit 1 Cursor c = resolver.query(uri, null, null, null, " id desc limit 1"); if(c.moveToNext()){ String string = "id="+ c.getInt(0) + ",name=" + c.getString(1) + ",address=" + c.getString(2); Log.i("MainActivity", string); Toast.makeText(MainActivity.this, string, 1).show(); } //父类未做任何操作 super.onChange(selfChange); } }; Uri uri = Uri.parse("content://com.bruce.contentprovider.demo/student"); getContentResolver().registerContentObserver(uri, true, observer); }