ContentProvider的总结

概述

在Android开发中采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据等等。
ContentProvider作为Android四大组件之一,一般为存储和获取数据提供统一的接口,可以在不同的应用程序之间共享数据。

ContentProvider的使用

1.ContentProvider的实现:
(1)新建类MyProvider.java继承ContentProvider,并实现其增删改查等六个方法。

方法名说明
onCreate主要用来初始化使用到的工具,在ContentProvider对象创建之后就会被调用。
query通过对数据库具有可读权限对象的query方法,完成外部应用数据库关于表的查询操作。
insert通过对数据库具有可写权限对象的insert方法,完成数据库关于表的插入操作。
delete通过对数据库具有可写权限对象的delete方法,完成数据库中关于表的删除操作。
update通过对数据库具有可写权限对象的update方法,完成数据库中关于表的更新操作。
getType用来标识ContentProvider中数据的类型。其中如果 URI 模式用于单个行为android.cursor.item/,如果 URI 模式用于多个行为android.cursor.dir/。

(2)在AndroidManifest.xml对ContentProvider进行配置,为了能让其他应用找到该ContentProvider ,ContentProvider采用了authorities(主机名/域名)对它进行唯一标识。

<provider
      android:authorities="com.example.myProvider"
      android:name=".MyProvider"/>

其中android:authorities 授权,表示外部应用程序访问当前内容提供者的标识符,一般是以 “包名 + 类名” 的形式来定义的。
android:name表示实现 ContentProvider 的类。
2.ContentProvider中的Uri:
比如:content://com.example.myProvider/table/666
格式为scheme://authority/Path/Id

字段说明
scheme为固定值content,表示访问内容提供者
authority授权信息,用以区别不同的ContentProvider,也就是清单文件中provider节点中的authorites属性
Path表名,用以区分ContentProvider中不同的数据表
IdId号,用以区别表中的不同数据

3.UriMatcher类:
UriMatcher类用来匹配Uri,使用match()方法匹配路径时返回匹配码。
addURI(authority, path, code)方法说明:

参数说明
authority用于标识唯一一个ContentProvider,和清单文件中的authorities属性相同
path路径,一般为表名,*表示匹配任意字符,#表示匹配数字
code返回值,匹配路径成功的返回值

比如:

private static final String AUTHORITY = "com.example.myProvider";
    private static final int MATCH_ALL_CODE = 200;
    private static final int MATCH_ONE_CODE = 201;
    private static UriMatcher uriMatcher;
    static{
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "student", MATCH_ALL_CODE);
        uriMatcher.addURI(AUTHORITY, "student/#", MATCH_ONE_CODE);
    }

其中”uriMatcher.addURI(AUTHORITY, “student/#”, MATCH_ONE_CODE);”
表示如果match(uri)方法匹配content://com.example.myProvider/student/#路径,返回匹配码为201。
4.ContentUris类:
ContentUris类用于操作Uri路径后面的ID部分,主要是两个方法。
(1)在Uri路径加上ID:

ContentUris.withAppendedId(uri, id);

(2)从Uri中获取ID:

long id = ContentUris.parseId(uri);

5.ContentResolver:
使用ContentResolver对象来对ContentProvider中的数据进行增删改查的操作或是监听数据的变化。
(1)插入数据:

ContentResolver contentResolver = getContentResolver();
                Uri uri = Uri.parse("content://com.example.myProvider/student");
                ContentValues contentValues = new ContentValues();
                contentValues.put("name", "Test");
                contentValues.put("phone", "123);
                contentResolver.insert(uri, contentValues);

(2)更新数据:

ContentResolver contentResolver = getContentResolver();
                Uri uri = Uri.parse("content://com.example.myProvider/student/1");
                contentValues = new ContentValues();
                contentValues.put("name", "newName");
                contentValues.put("phone", "456);
                contentResolver.update(uri, contentValues, null, null);

(3)删除数据:

ContentResolver contentResolver = getContentResolver();
                Uriuri = Uri.parse("content://com.example.myProvider/student/1");
                contentResolver.delete(uri, null, null);

(4)查找数据:

ContentResolver contentResolver = getContentResolver();
        Uri uri = Uri.parse("content://com.example.myProvider/student");
        Cursor cursor = contentResolver.query(uri, null, null, null, "id asc");
        while(cursor.moveToNext()){
            int id = cursor.getInt(cursor.getColumnIndex("id"));
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String phone = cursor.getString(cursor.getColumnIndex("phone"));
        }
        cursor.close();

(5)监听数据变化:
以插入数据时监听数据变化为例:
第一:在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册此URI上的访问者:

case MATCH_ONE_CODE:
                id = db.insert("student", null, values);
                String path = uri.toString();
                getContext().getContentResolver().notifyChange(uri, null);
                return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id);

第二:使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:

private class StudentContentObserver extends ContentObserver
    {
        public StudentContentObserver(Handler handler)
        {
            super(handler);
        }

        // 得到数据的变化通知
        @Override
        public void onChange(boolean selfChange)
        {
            Log.d("xxx", "change");
            Toast.makeText(MainActivity.this, "数据发生变化", Toast.LENGTH_LONG).show();
        }
    }

contentResolver = getContentResolver();             contentResolver.registerContentObserver(Uri.parse("content://com.example.myProvider/student"), true, new StudentContentObserver(new Handler()));

6.主要代码:
MyProvider.java:

public class MyProvider extends ContentProvider{
    private StudentOpenHelper helper;
    private static final String AUTHORITY = "com.example.myProvider";
    private static final int MATCH_ALL_CODE = 200;
    private static final int MATCH_ONE_CODE = 201;
    private static UriMatcher uriMatcher;
    // 数据集的MIME类型字符串以vnd.android.cursor.dir/开头
    public static final String PERSONS_TYPE = "vnd.android.cursor.dir/vnd.com.example.myProvider.student";
    // 单一数据的MIME类型字符串以vnd.android.cursor.item/开头
    public static final String PERSONS_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.example.myProvider.student";
    static{
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "student", MATCH_ALL_CODE);
        uriMatcher.addURI(AUTHORITY, "student/#", MATCH_ONE_CODE);
    }
    @Override
    public boolean onCreate() {
        helper = new StudentOpenHelper(getContext());
        return true;
    }

    @Nullable
    @Override//查找
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        SQLiteDatabase db = helper.getReadableDatabase();
        int flag = uriMatcher.match(uri);
        switch (flag){
            case MATCH_ALL_CODE:
                return db.query("student", projection, selection, selectionArgs, null, null, null);
            case MATCH_ONE_CODE:
                long id = ContentUris.parseId(uri);
                String where = "id=" + id;
                where += !TextUtils.isEmpty(selection) ? "and("+selection+")" : "";
                return db.query("student", projection, where, selectionArgs, null, null, null);
            default:
                throw new IllegalArgumentException("Unknown URI:" + uri);

        }
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)) {
            case MATCH_ALL_CODE:
                return PERSONS_TYPE;
            case MATCH_ONE_CODE:
                return PERSONS_ITEM_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Nullable
    @Override//插入
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        SQLiteDatabase db = helper.getWritableDatabase();
        int flag = uriMatcher.match(uri);
        long id = 0;
        switch (flag){
            case MATCH_ALL_CODE:
                id = db.insert("student", null, values);
                getContext().getContentResolver().notifyChange(uri, null);
                return ContentUris.withAppendedId(uri, id);
            case MATCH_ONE_CODE:
                id = db.insert("student", null, values);
                String path = uri.toString();
                getContext().getContentResolver().notifyChange(uri, null);
                return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id);
            default:
                throw new IllegalArgumentException("Unknown URI:"+uri);
        }
    }

    @Override//删除
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        int flag = uriMatcher.match(uri);
        int count = 0;
        switch(flag){
            case MATCH_ALL_CODE:
                count = db.delete("student", selection, selectionArgs);
                break;
            case MATCH_ONE_CODE:
                long id = ContentUris.parseId(uri);
                String where = "id=" + id;
                where += !TextUtils.isEmpty(selection) ? "and(" + selection +")" : "";
                count = db.delete("student", where, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI:"+uri);
        }
        return count;
    }

    @Override//更新
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        int flag = uriMatcher.match(uri);
        int count = 0;
        switch(flag){
            case MATCH_ALL_CODE:
                count = db.update("student", values, selection, selectionArgs);
                break;
            case MATCH_ONE_CODE:
                long id = ContentUris.parseId(uri);
                String where = "id=" + id;
                where += !TextUtils.isEmpty(selection) ? "and(" + selection +")" : "";
                count = db.update("student", values, where, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI:"+uri);
        }
        return count;
    }
}

MainActivity.java:

public class MainActivity extends Activity implements View.OnClickListener{
    private Button insert_btn;
    private Button query_btn;
    private Button update_btn;
    private Button delete_btn;
    private ListView listView;
    private MyAdapter adapter;
    private EditText name_et;
    private EditText phone_et;
    ContentResolver contentResolver;

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

    private void initView(){
        insert_btn = (Button) this.findViewById(R.id.insert_btn);
        query_btn = (Button) this.findViewById(R.id.query_btn);
        update_btn = (Button) this.findViewById(R.id.update_btn);
        delete_btn = (Button) this.findViewById(R.id.delete_btn);
        insert_btn.setOnClickListener(this);
        query_btn.setOnClickListener(this);
        update_btn.setOnClickListener(this);
        delete_btn.setOnClickListener(this);
        name_et = (EditText) this.findViewById(R.id.name_et);
        phone_et = (EditText) this.findViewById(R.id.phone_et);
        listView = (ListView) this.findViewById(R.id.listView);
        adapter = new MyAdapter(this, getStudents());
        listView.setAdapter(adapter);
    }

    private class StudentContentObserver extends ContentObserver
    {
        public StudentContentObserver(Handler handler)
        {
            super(handler);
        }

        // 得到数据的变化通知
        @Override
        public void onChange(boolean selfChange)
        {
            Toast.makeText(MainActivity.this, "数据发生变化", Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.insert_btn://在表中插入数据
                contentResolver = getContentResolver();
                //注册监听
                contentResolver.registerContentObserver(Uri.parse("content://com.example.myProvider/student"), true, new StudentContentObserver(new Handler()));
                Uri uri = Uri.parse("content://com.example.myProvider/student");
                ContentValues contentValues = new ContentValues();
                contentValues.put("name", name_et.getText().toString());
                contentValues.put("phone", phone_et.getText().toString());
                Uri newUri = contentResolver.insert(uri, contentValues);
                adapter.setStudents(getStudents());
                adapter.notifyDataSetChanged();
                break;
            case R.id.update_btn://更新id为1的数据
                contentResolver = getContentResolver();
                uri = Uri.parse("content://com.example.myProvider/student/1");
                contentValues = new ContentValues();
                contentValues.put("name", name_et.getText().toString());
                contentValues.put("phone", phone_et.getText().toString());
                contentResolver.update(uri, contentValues, null, null);
                adapter.setStudents(getStudents());
                adapter.notifyDataSetChanged();
                break;
            case R.id.query_btn://查询数据
                adapter.setStudents(getStudents());
                adapter.notifyDataSetChanged();
                break;
            case R.id.delete_btn://删除id为1的数据
                contentResolver = getContentResolver();
                uri = Uri.parse("content://com.example.myProvider/student/1");
                contentResolver.delete(uri, null, null);
                adapter.setStudents(getStudents());
                adapter.notifyDataSetChanged();
                break;
        }
    }

    /**
     * 查询数据库,获取student表中数据集合
     * @return
     */
    private List<Student> getStudents(){
        List<Student> students = new ArrayList<>();
        ContentResolver contentResolver = getContentResolver();
        Uri uri = Uri.parse("content://com.example.myProvider/student");
        Cursor cursor = contentResolver.query(uri, null, null, null, "id asc");
        while(cursor.moveToNext()){
            int id = cursor.getInt(cursor.getColumnIndex("id"));
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String phone = cursor.getString(cursor.getColumnIndex("phone"));
            Student student = new Student(id, name, phone);
            students.add(student);
        }
        cursor.close();
        return students;
    }
}

demo效果:
这里写图片描述
完整demo请点击这里
参考文档:
https://developer.android.com/guide/topics/providers/content-provider-creating.html?hl=zh-cn
http://www.cnblogs.com/gaopeng527/p/4591750.html
http://www.jianshu.com/p/d5d5b68c3acb
http://www.cnblogs.com/linjiqin/archive/2011/05/28/2061396.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值