西甲2015赛程表
最新安卓入门教程
扫码关注
获取更多技术干货

image

作者论坛ID:hbxfyxw    

版权声明:本章节为安卓巴士博主原创文章,未经授权不得以?#25105;廡问?#36716;载发布/发表,违者将依法追究责任


7.1 内容提供者简介

内容提供者,?#24067;碈ontentProvider,是Android中的四大组件之一。从这里也能知道它在Android开发中的的重要性,所以是必须要掌握的了。同时它?#24425;?#22235;大组件里面最简单最容易入手的一个。ContentProvider是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。有点像调用web接口一样,我们在的开发的时候看不到存在数据库里面的数据,但是我们只要知道了接口地址后,按照对应的规则进行调用,就可以获取到数据。差不多是一样的用法。

7.2 内容提供者机制简单讲解

调用过程

image

在创建ContentProvider前,首先要实现底层的数据源,数据源包括数据库、文件系统或网络等,然后?#22363;蠧ontentProvider类中实?#21482;?#26412;数据操作的接口函数。调用者不能直接调用ContentProvider的接口函数,需要通过ContentResolver对象,通过URI间接调用ContentProvider。

交互关系

在ContentResolver对象与ContentProvider进行交互时,通过URI确定要访问的ContentProvider数据集。在发起的一个请求的过程中,Android系统根据URI确定处理这个查询的ContentProvider,然后初始化ContentProvider所?#34892;?#35201;的资源,这个初始化的工作是Android系统完成的,无需开发人员关心。一般情况下只有一个ContentProvider对象,但却可以同时与多个ContentResolver进行交互。

所需权限

根据功能需要自己进行添加 例如在开发读取通讯录功能的时候,所需的权限是下面:

<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

在开发读取短信功能的时候,所需的权限是下面:

<uses-permission android:name="android.permission.READ_SMS" />

根据自己开发的项目灵活进行配置

数据来源

在Android系?#25345;校珻ontentProvider共享的数据多来自系统?#28304;?#24212;用,比如联系人信息,图片库,音频库等应用,或者是共享自己或者其他开发者开发的应用里面的文件、数据库内存储的数据。

ContentResolver

ContentResolver:内容解析器,是为了方便在应用之间交换数据。
当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序可以通过提供ContentProvider来实现; 而其他应用程序需要使用这些数据时,不管提供数据的应用程序是否启动,可以通过ContentResolver来操作ContentProvider暴露的数据。包括增加数据insert()、删除数据delete()、修改数据update()、查询数据query()?#21462;?虽然大部分使用ContentProvider操作的数据都来自于数据库,但是也可以来自于文件、SharedPreferences、XML或网络等其他存储方式。

URI

Uri统一资源标识符:Uri是ContentResolver和ContentProvider进行数据交换的标识。 形如:content://com.qq.contacts/user/1
其中标准前缀协议部分:以“content://”开头,表明是以ContentProvider的方式进行数据交换。
Uri的authority部分:"com.qq.contacts"该部分是暴露数据的app数据的包名。 Uri的path部分,user,表明判断请求的路径
Uri的id部分,表明请求要操作的id值;如果不是操作具体某一id的数据,此部分可以去除。

7.3 访问其他应用中的数据

这一部分开始到代码实战部分了,先前讲到ContentProvider可以读取其他应用的联系人、短信、通话记录、音频文件数据等?#21462;?#36825;一部分以具体的例子来实际熟悉下用法。最常见的就是读取手机联系人了。

ContentResolver的基本用法 

ContentResolver是通过URI来查询ContentProvider中提供的数据。除了URI以外,还必须知道需要获取的数据段的名称,以?#25353;?#25968;据段的数据类型。如果你需要获取一个特定的记录,你就必须知道当前记录的ID,也就是URI中D部分。

前面也提到了ContentProvider是以类似接口的方式将数据暴露出去,那么ContentResolver也将采用类似数据库的操作来从ContentProvider中获取数据。下面是ContentResolver的主要方法:  

  • query(Uri, String[], String, String[], String) 返回 final Cursor
    query方法的参数依次为:请求的Uri,列名数组,查询条件,selectionArgs替换占位符的数组,排序sortOrder语句
  • insert(Uri, ContentValues) 返回 final Uri
    insert方法的参数依次为:请求的Uri,传递的参数ContentValues
  • update(Uri, ContentValues, String, String[]) 返回final int
    update方法的参数依次为:请求的Uri,传递的参数ContentValues,String实例对象,String引用对象数组
  • delete(Uri, String, String[]) 返回 final int
    delete方法的参数依次为:请求的Uri,String实例对象,String数组

读取系统联系人 

//  读取系统联系人示例
//  在AndroidManifest.xml中添加访问联系人数据的权限  
    private void readContacts() {  
        Cursor cursor = null;  
        try {  
            //查询联系人数据  
            //ContactsContract.CommonDataKinds.Phone类已经封装好了URI,NAME,NUMBER等信息  
            cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,  
                    null, null, null, null);  
            while (cursor.moveToNext()) {  
                //获取联系人姓名  
                String displayName = cursor.getString(cursor  
                        .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));  
                //获取联系人手机号  
                String number = cursor.getString(cursor  
                        .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));  
                contactsList.add(displayName + "\n" + number);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (cursor != null) {  
                cursor.close();  
            }  
        }  
    }  

注意:清单文件里面添加权限声明:

<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

7.4 创建自己的内容提供者

前面说到我们开发的应用去读取系统应用的数据(例如:通讯录、短信、音频数据等),那么我们是否可以自己在开发应用的时候,将本应用的数据以内容提供者的方?#25945;?#20379;给别的应用来操作呢?当然?#24425;?#21487;以的。
我们所要做的就是?#22363;蠧ontentProvider这个抽象类,然后重写它里面的各种方法。
外部开发者可以通过我们定义的Uri及传值规则来操作数据的增删改查。

示例代码

public class MyContentProvider extends ContentProvider {
    private final static int CONTACT = 1;

    private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        uriMatcher.addURI("com.abc.mycontentprovider","contact",CONTACT);
    }

    private MyDBHelp dbHelp;

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int id =0;
        if(uriMatcher.match(uri) == CONTACT){
            SQLiteDatabase database = dbHelp.getWritableDatabase();
            id= database.delete("contact", selection, selectionArgs);
            contentResolver.notifyChange(uri,null);
        }
       return id;
    }

    @Override
    public String getType(Uri uri) {
        // TODO: Implement this to handle requests for the MIME type of the data
        // at the given URI.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri u = null;
        if(uriMatcher.match(uri) == CONTACT){
            SQLiteDatabase database = dbHelp.getWritableDatabase();

            long d = database.insert("contact", "_id", values);
            u = ContentUris.withAppendedId(uri,d);
            contentResolver.notifyChange(u,null);
        }
        return u;

    }
    private ContentResolver contentResolver;
    @Override
    public boolean onCreate() {
        Context context = getContext();
        contentResolver = context.getContentResolver();
        dbHelp = new MyDBHelp(context,"contact.db",null,1);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        Cursor cursor = null;
        if(uriMatcher.match(uri) == CONTACT){
            SQLiteDatabase database = dbHelp.getReadableDatabase();
            cursor = database.query("contact", projection, selection, selectionArgs, null, null, sortOrder);
            cursor.setNotificationUri(contentResolver,uri);
        }
        return cursor;

    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    private static  class MyDBHelp extends SQLiteOpenHelper{

        public MyDBHelp(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);

        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            String sql = "create table contact(_id integer primary key autoincrement," +
                    "name text not null,number text not null);";
            db.execSQL(sql);
        }

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

        }
    }
}

在清单文件里面对新增的自定义ContentProvider加以声明。例如:

<provider
    android:name=".MyContentProvider"
    android:authorities="com.abc.MyContentProvider"
    android:exported="true"
    />

authorities 指明内容提供者的唯一标识,外部其他的应用来调用的时候通过此标识来找到
exported true意为允许外部的其他应用访问

接下来写另一个应用程序,作为调用的一方通过ContentProvider去读取上一个应用程序里面暴露的方法,进而获取或者操作所需的数据。 在另一个应用里面,那么它要访问的Uri就为

 Uri uri = Uri.parse("content://com.abc.mycontentprovider/contact")

其访问数据及增删改的操作类?#21462;?.3访问其他应用数据》中的示例。

7.5 小结与点评

欢迎大家提出完善意见以补充。


欢迎大家对本教程的内容进行刊错和纠正,点击此处?#24052;?#35770;坛给你?#19981;?#30340;文章作者给予支持鼓励,若有问题反馈和建议请注明具体章节
西甲2015赛程表 塔什干火车头vs希拉尔 卡迪夫城对阿斯顿维拉 宁夏11选5开奖结果查询 中彩网双色球 神秘的诱惑送彩金 罗马字体 完全仿盛大传奇手游 银河大战在线客服 布莱顿对埃弗顿 重庄时时彩开奖记录