zoukankan      html  css  js  c++  java
  • Android基础内容提供者ContentProvider的使用详解(转)

    1.什么是ContentProvider

    首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少。 ContentProvider为不同的软件之间数据共享,提供统一的接口。也就是说,如果我们想让其他的应用使用我们自己程序内的数据,就可以使用 ContentProvider定义一个对外开放的接口,从而使得其他的应用可以使用咱们应用的文件、数据库内存储的信息。当然,自己开发的应用需要给其 他应用共享信息的需求可能比较少见,但是在Android系 统中,很多系统自带应用,比如联系人信息,图片库,音频库等应用,为了对其他应用暴露数据,所以就使用了ContentProvider机制。所以,我们 还是要学习ContentProvider的基本使用,在遇到获取联系人信息,图片库,音频库等需求的时候,才能更好的实现功能 。

    2.如何定义一个ContentProvider

    Android系统为了让我们更好的对外暴露数据,提供了统一的接口,所以定义了抽象类ContentProvider,因此,如果我们想对外提供数据,我们需要继承ContentProvider,并且实现下面的这几个方法:
    onCreate() 当我们的provider初始化时被调用,我们应该在这个方法里面完成部分初始化操作 query() 查询方法,用于给调用者返回数据 insert() 插入操作,用于让外部应用插入数据到内容提供者中 update() 更新操作,用于更新内容提供者的数据 delete() 用于删除数据 getType 返回内容提供者的MIME Type
    上面这些方法,当我们继承自ContentProvider的时候,eclipse会自动的给我们添加,但是这并不代表我们每个方法都需要自定义实现。如 果我们只希望给其他应用提供数据,而不允许其他应用修改我们的数据,那么我们只需要实现onCreate(),getType()和query()这三个 方法就可以了,其他的三个方法我们可以根据业务需求,实现或者是不实现。
    因为一般使用ContentProvider向外部暴露数据库的信息,因此,本篇将以使用ContentProvider向其他应用暴露数据库信息为例,讲解ContentProvider的基本使用。
    Android中SQLite数据库的创建和使用,本篇不再介绍,不清楚的请看这篇文章 SQLite数据库的简单实用。

    /**
     * 内容提供者
     * 
     * @author ZhaoKaiQiang
     * @time 2014年6月6日
     */
    public class StudentProvider extends ContentProvider {
        // 数据库操作类,用于获取SQLiteDatabase
        private MyDbOpenHelper dbHelper;
    
        private static final int STUDENT = 1;
        private static final int STUDENTS = 2;
    
        // UriMatcher类是一个很重要的类,因为我们需要根据传入的uri,来判断执行相对应的操作
        private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
    
        // 静态代码块用于初始化MATCHER需要匹配的uri
        static {
            // MATCHER.addURI(主机名(用于唯一标示一个ContentProvider,这个需要和清单文件中的authorities属性相同),路径(可以用来表示我们要操作的数据,路径的构建应根据业务而定),返回值(用于匹配uri的时候,作为匹配的返回值));
            MATCHER.addURI("com.example.mydbdemo.StudentProvider", "student", STUDENTS);
            MATCHER.addURI("com.example.mydbdemo.StudentProvider", "student/#", STUDENT);
        }
    
        // 进行数据的初始化操作
        @Override
        public boolean onCreate() {
            dbHelper = new MyDbOpenHelper(getContext());
            return false;
        }
    
        // 查询
        // 如果uri为        content://com.example.mydbdemo.StudentProvider/student
        // 则代表查询所有的student表内的数据
        // 如果uri为        content://com.example.mydbdemo.StudentProvider/student/6
        // 则代表查询student表内id=6的数据
        @Override
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            //判断传入的uri到底匹配哪一个,从而实现不同的业务需求
            switch (MATCHER.match(uri)) {
            //查询全部的学生信息
            case STUDENTS:
                //db.query(表明, 要查询的列(是一个String数组), where条件, where条件中的参数, groupBy, having, sortOrder);
                return db.query("student", projection, selection, selectionArgs, null, null, sortOrder);
            //查询某一个id对应的学生的信息
            case STUDENT:
                //取出我们要查询的数据的id
                long id = ContentUris.parseId(uri);
                String where = "id=" + id;
                //将selection查询信息拼接到我们的where条件中
                if (selection != null && !"".equals(selection)) {
                    where = selection + " and " + where;
                }
                return db.query("student", projection, where, selectionArgs, null, null, sortOrder);
            //如uri不匹配,抛出不合法参数的异常
            default:
                throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
            }
    
        }
    
        // 插入
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            switch (MATCHER.match(uri)) {
            case STUDENTS:
                long id = db.insert("student", "name", values);
                return ContentUris.withAppendedId(uri, id);
            default:
                throw new IllegalArgumentException("Uri不匹配");
            }
    
        }
    
        //删除数据
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int count = 0;
            switch (MATCHER.match(uri)) {
            case STUDENTS:
                count = db.delete("student", selection, selectionArgs);
                return count;
    
            case STUDENT:
                long id = ContentUris.parseId(uri);
                String where = "id=" + id;
                if (selection != null && !"".equals(selection)) {
                    where = selection + " and " + where;
                }
                count = db.delete("student", where, selectionArgs);
                return count;
    
            default:
                throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
            }
        }
    
        //更新数据
        @Override
        public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int count = 0;
            switch (MATCHER.match(uri)) {
            case STUDENTS:
                count = db.update("student", values, selection, selectionArgs);
                return count;
    
            case STUDENT:
                long id = ContentUris.parseId(uri);
                String where = "id=" + id;
                if (selection != null && !"".equals(selection)) {
                    where = selection + " and " + where;
                }
                count = db.update("student", values, where, selectionArgs);
                return count;
    
            default:
                throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
            }
        }
    
        // 用于获取MIME Type
        @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("Unkwon Uri:" + uri.toString());
            }
    
        }
    
    }

    我们在定义好我们的ContentProvider之后,因为ContentProvider数据四大组件之一,因此我们还需要在AndroidManifest清单文件中进行注册才能使用,下面是注册信息

    <!-- 不要忘记exported这个属性,如果不加,可能会导致外部程序访问失败,错误信息为权限拒绝 -->
             <!-- authorities这个属性就是我们在ContentProvider中使用的addURI方法时的第一个参数的取值 -->
            <provider
                android:name="com.example.mydbdemo.StudentProvider"
                android:exported="true"
                android:authorities="com.example.mydbdemo.StudentProvider" >
            </provider>

    注意,provider的声明和activity一样,都是在application节点进行声明的。
    至此,我们就完成了我们自己的ContentProvider的生命,其他的应用现在就可以使用我们往外部暴露的数据信息了。

    3.外部应用如何使用我们的ContentProvider

    我们已经定义好了我们自己的ContentProvider,那么外部应用如何调用呢? 下面,我将新建一个测试单元工程,完成对ContentProvider的各个方法的测试
    添加方法测试

    //使用ContentProvider添加数据的测试
        public void testadd() throws Throwable {
            //获取ContentResolver对象,完成对ContentProvider的调用
            ContentResolver contentResolver = this.getContext().getContentResolver();
            //构建我们的uir,这个uri
            Uri insertUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student");
            ContentValues values = new ContentValues();
            values.put("name", "zhaokaikai");
            values.put("age", 91);
            values.put("school", "bbbb");
            //返回值为我们刚插入进入的数据的uri地址
            Uri uri = contentResolver.insert(insertUri, values);
            Log.i(TAG, uri.toString());
        }

    删除方法测试

    //使用ContentProvider删除数据的测试
        public void testDelete() throws Throwable {
            ContentResolver contentResolver = this.getContext().getContentResolver();
            //删除id为6的学生信息
            Uri deleteUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6");
            contentResolver.delete(deleteUri, null, null);
        }

    修改方法测试

    //使用ContentProvider更新数据的测试
        public void testUpdate() throws Throwable {
            ContentResolver contentResolver = this.getContext().getContentResolver();
            //更新id = 6 的学生信息
            Uri updateUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6");
            ContentValues values = new ContentValues();
            values.put("name", "testUp");
            values.put("age", "101");
            values.put("school", "ccccc");
            contentResolver.update(updateUri, values, null, null);
        }
    //使用ContentProvider查询数据的测试
        public void testFind() throws Throwable {
            ContentResolver contentResolver = this.getContext().getContentResolver();
            //这个uri用于查询所有的数据,若查询某个id的数据,则构建下面的uri
            //Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/要查询的id");
            Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student");
            Cursor cursor = contentResolver.query(selectUri, null, null, null, "id desc");
            while (cursor.moveToNext()) {
                int id = cursor.getInt(cursor.getColumnIndex("id"));
                String name = cursor.getString(cursor.getColumnIndex("name"));
                int age = cursor.getInt(cursor.getColumnIndex("age"));
                String school = cursor.getString(cursor.getColumnIndex("school"));
                Log.i(TAG, "id=" + id + ",name=" + name + ",age=" + age +",school="+school);
            }
        }

    上面的方法都经过了单元测试。

    其他人的总结:{

    二、Uri类简介

    Uri代表了要操作的数据,Uri主要包含了两部分信息
    ①需要操作的ContentProvider
    ②对ContentProvider中的什么数据进行操作

    组成部分
    ①scheme:ContentProvider的scheme已经由Android所规定为content://
    ②主机名(Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。建议为公司域名,保持唯一性
    ③路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定:

    要操作person表中id为10的记录
    content://cn.xyCompany.providers.personProvider/person/10

    要操作person表中id为10的记录的name字段
    content://cn.xyCompany.providers.personProvider/person/10/name

    要操作person表中的所有记录
    content://cn.xyCompany.providers.personProvider/person

    要操作的数据不一定来自数据库,也可以是文件等他存储方式,如要操作xml文件中user节点下的name节点

    content://cn.xyCompany.providers.personProvider/person/10/name

    把一个字符串转换成Uri,可以使用Uri类中的parse()方法
    Uri uri = Uri.parse(“content://cn.xyCompany.providers.personProvider/person”)

    三、UriMatcher、ContentUris和ContentResolver简介

    Uri代表了要操作的数据,所以经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris。掌握它们的使用会便于我们的开发工作。

    UriMatcher

    用于匹配Uri

    ①把需要匹配Uri路径全部给注册上

    // 常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
    UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    // 若match()方法匹配content://cn.xyCompany.providers.personProvider/person路径则返回匹配码为1
    uriMatcher.addURI(“content://cn.xyCompany.providers.personProvider”,”person”, 1);

    // 若match()方法匹配content://cn.xyCompany.providers.personProvider/person/10路径则返回匹配码为2
    uriMatcher.addURI(“content://cn.xyCompany.providers.personProvider”,”person/#”, 1);

    ②注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配

    ContentUris
    ContentUris是对URI的操作类,其中的withAppendedId(uri, id)用于为路径加上ID部分,parseId(uri)方法用于从路径中获取ID部分方法很实用。
    Uri insertUri = Uri.parse(“content://cn.xyCompany.providers.personProvider/person” + id);等价于
    Uri insertUri = ContentUris.withAppendedId(uri, id);

    ContentResolver
    当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成。要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法来操作数据。
    }

  • 相关阅读:
    vue iview 导入excel文件(upload)
    iview table 中用根据不同状态改变颜色(用render)
    vue项目中导出excel表格数据
    iview table 中 render 时间格式化
    微信浏览器的部分特效更接近浏览器IE 9
    ABP 拦截器不工作
    vue + webpack 添加的引用不编译成ES6的问题
    把vue组件添加到body下
    vue+vuex+router实现阻止浏览器回退
    webpack使用vue-moment-libs 在PC微信浏览器下显示空白
  • 原文地址:https://www.cnblogs.com/dayiran1222/p/5586544.html
Copyright © 2011-2022 走看看