您的位置:首页 > 移动开发 > Android开发

android 四大组件之ContentProvider

2017-05-04 22:54 316 查看
  ContentProvider是android四大组件之一,从名字可以看出,就是内容提供者,让其他app可以访问到该应用暴露的数据,实际上也是如此,一般情况下,不会用到ContentProvider,但是获取联系人,也就间接的使用到了,下面简单介绍下ContentProvider的使用

1.创建一个ContentProvider的实现类:

  新建一个类并继承ContentProvider的类,四大组件都是如此做的,ContentProvider是一个抽象类, 有六个抽象方法 onCreate、getType、delete、update、insert和query,并从写这六个方法



  看到delete、update、insert和query这些方法,刚好对应着数据的增删改查四个方法,这些用于供外部应用往ContentProvider增删改查数据,其实的确如此。onCreate方法,该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建,getType方法,该方法用于返回当前Url所代表数据的MIME类型

getType方法

  1)如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,

  例如:要得到所有person记录的Uri为content://com.app.wurui.providerdemo.myprovider/person,那么返回的MIME类型字符串应该为:”vnd.android.cursor.dir/person”。

  2)如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,

  例如:得到id为10的person记录,Uri为content://com.app.wurui.providerdemo.myprovider/person/10,那么返回的MIME类型字符串为:”vnd.android.cursor.item/person”

2.注册

  也是在<\application>节点下进行注册



3.外部访问地址

  1)、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据

  2)、Android所提供的ContentProvider都存放在android.provider包中。 将其分为A,B,C,D 4个部分,也可以使用三部分,去掉D部分:



  A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;”content://”

  B:URI 的标识,用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称

  

  C:路径(path),通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就可以了; “content://com.app.wurui.providerdemo.myprovider/person/1”

  

  D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; “content://com.app.wurui.providerdemo.myprovider/person/tablename/#” #表示数据id

4.UriMatcher类和ContentUris类介绍

  在应用ContentProvider之前,先了解俩个类,是android系统专门为ContentProvider提供解析Uri的工具类

1).UriMatcher类

   该类提供了两个方法,addURI 和match方法,主要用于匹配Uri



2).ContentUris类

   该类提供了三个静态方法,withAppendedId、parseId和appendId方法



   上面几个方法,注释写的很清楚,在此不在解释了

5.ContentProvider的简单实例 这里用数据库来存储数据

  此处不介绍数据库

public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}

public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
super(context, name, factory, version, errorHandler);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table person(_id integer primary key autoincrement, name varchar)");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}
}


public class MyProvider extends ContentProvider {
private DBHelper mDBHelper;
private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

static {
mUriMatcher.addURI("com.app.wurui.providerdemo.myprovider", "person", 1);
mUriMatcher.addURI("com.app.wurui.providerdemo.myprovider", "person/#", 2);
}

@Override
public boolean onCreate() {
mDBHelper = new DBHelper(getContext(), "wurui.db", null, 1);
return false;
}

@Nullable
@Override//此方法如果正常返回不能关闭数据库连接,projection查询的条目, selection 条件 selectionArgs 条件的参数 sortOrder 排序
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
SQLiteDatabase database = mDBHelper.getReadableDatabase();
long code = mUriMatcher.match(uri);
Cursor cursor = null;
if(code == 1){
cursor = database.query("person", projection, selection, selectionArgs, null, null, sortOrder);
} else if(code == 2){
long id = ContentUris.parseId(uri);
cursor = database.query("person", null, new String("_id = ?"), new String[]{String.valueOf(id)}, null, null, null);
} else {
database.close();
new RuntimeException("Uri不合法");
}
return cursor;
}

@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}

@Nullable
@Override //values 添加的数据 返回的是添加进去的Uri
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
SQLiteDatabase database = mDBHelper.getReadableDatabase();
long code = mUriMatcher.match(uri);
Uri result = null;
if(code == 1){
long id = database.insert("person", null, values);
result = ContentUris.withAppendedId(uri, id);
} else {
database.close();
new RuntimeException("Uri不合法");
}
database.close();
return result;
}

@Override//返回值是删除了多少条数据
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase database = mDBHelper.getReadableDatabase();
long code = mUriMatcher.match(uri);
int deleteCount = 0;
if(code == 1){
deleteCount = database.delete("person", selection, selectionArgs);
} else if(code == 2){
long id = ContentUris.parseId(uri);
deleteCount = database.delete("person", "_id = ?", new String[]{String.valueOf(id)});
} else {
database.close();
new RuntimeException("Uri不合法");
}
database.close();
return deleteCount;
}

@Override//返回值是更新了多少条数据
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase database = mDBHelper.getReadableDatabase();
long code = mUriMatcher.match(uri);
int updateCount = 0;
if(code == 1){
updateCount = database.update("person", values, selection, selectionArgs);
} else if(code == 2){
long id = ContentUris.parseId(uri);
updateCount = database.update("person", values, "_id = ?", new String[]{String.valueOf(id)});
} else {
database.close();
new RuntimeException("Uri不合法");
}
database.close();
return updateCount;
}
}


  ContentProvider就写好了,为了验证是否正确,在另一个app调用

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

<Button
android:id="@+id/insert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="insert"/>

<Button
android:id="@+id/query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="query"/>

<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="update"/>

<Button
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="delete"/>

</LinearLayout>


public class MainActivity extends AppCompatActivity {
private int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyOnClickListener listener = new MyOnClickListener();
findViewById(R.id.insert).setOnClickListener(listener);
findViewById(R.id.delete).setOnClickListener(listener);
findViewById(R.id.query).setOnClickListener(listener);
findViewById(R.id.update).setOnClickListener(listener);
}

class MyOnClickListener implements View.OnClickListener{

@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.insert:
insert();
break;
case R.id.delete:
delete();
break;
case R.id.update:
upData();
break;
case R.id.query:
query();
break;
}
}
}

private void upData() {
ContentResolver resolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("name", "345");
int count = resolver.update(Uri.parse("content://com.app.wurui.providerdemo.myprovider/person"), values, null,  null);
System.out.println("更新了" + count + "条----------------------------------------");
}

private void delete() {
ContentResolver resolver = getContentResolver();
int count = resolver.delete(Uri.parse("content://com.app.wurui.providerdemo.myprovider/person"), "_id = ?", new String[]{String.valueOf(i)});
System.out.println("删除了" + count + "条----------------------------------------");
--i;
}

private void insert() {
ContentResolver resolver = getContentResolver();
ContentValues valus = new ContentValues();
valus.put("name", "wurui" + i);
Uri uri = resolver.insert(Uri.parse("content://com.app.wurui.providerdemo.myprovider/person"), valus);
++i;
Cursor cursor = resolver.query(uri, null, null, null, null);
if(cursor != null){
if(cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex("name"));
int id = cursor.getInt(cursor.getColumnIndex("_id"));
System.out.println("新增的数据   _id = " + id + " name = " + name + "----------------------------------------");
}
}
}

private void query() {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.app.wurui.providerdemo.myprovider/person");
Cursor cursor = resolver.query(uri, null, null, null, null);
if(cursor != null){
while (cursor.moveToNext()){
int id = cursor.getInt(0);
String name = cursor.getString(1);
System.out.println("id = " + id + " name = " + name);
}
cursor.close();
}
}
}


   以上就简单实现了ContentProvider的实例

6.监听ContentProvider中数据的变化

  1.继承ContentObserver类,并重写onChange方法

public class MyObserver extends ContentObserver {
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public MyObserver(Handler handler) {
super(handler);
}

@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
System.out.println("改变了");
}

}


  2.1注册对指定Uri的监听函数,一旦该Uri指向的内容发生改变,将通知到MyObserver类的onChange方法

getContentResolver().registerContentObserver(Uri.parse("content://com.app.wurui.providerdemo.myprovider/person"), true, mMyObserver);


  2.2当程序退出或者不需要再监听Uri的变化时,要主动取消对Uri的监听

if(mMyObserver != null){
getContentResolver().unregisterContentObserver(mMyObserver);
mMyObserver = null;
}


  3.在ContentProvider里,每当特定Uri上的数据发生变化,要触发对调用者对通知。通知使用ContentResolver的notifyChange()方法触发。比如删除数据时:

@Override//返回值是删除了多少条数据
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase database = mDBHelper.getReadableDatabase();
long code = mUriMatcher.match(uri);
int deleteCount = 0;
if(code == 1){
deleteCount = database.delete("person", selection, selectionArgs);
} else if(code == 2){
long id = ContentUris.parseId(uri);
deleteCount = database.delete("person", "_id = ?", new String[]{String.valueOf(id)});
} else {
database.close();
new RuntimeException("Uri不合法");
}
//当删除数据成功时,就会触发
getContext().getContentResolver().notifyChange(uri, null);
database.close();
return deleteCount;
}




  ContentProvider就讲到这里,相信大家对ContentProvider非常熟悉了、、、、、、、
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 数据