Android笔记---四大组件之Content Provider内容提供者详解

来源:互联网 发布:如何评价李中莹 知乎 编辑:程序博客网 时间:2024/04/30 08:48

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

我们先看下ContentProvider中需要掌握的知识点:
1.URI字符串
2.ContentResolve类
3.UriMatcher类
4.ContentUris类

ContentProvider是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”,外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样有增删改查的方式,不过在方法参数上稍微有一些区别,所以我们首先需要找到我们的“数据表”,而这是通过一个URI字符串来确定的。

URI字符串由以下三部分组成:
1.scheme: 规定为content://
2.主机名(Authority): 用于唯一标识这个ContentProvider,外部调用可以根据这个标识来找到它,一般为了避免冲突, 都会采用程序包名的方式来进行命名
3.路径(path): 用于对同一应用程序中不同的表做区分的, 添加在权限的后面,eg:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name

在得到了内容URI字符串之后, 我们还需要将它解析成 Uri 对象才可以作为参数传入,只需要调用 Uri.parse()方法, 就可以将内容URI字符串解析成 Uri 对象了,加入我们需要对程序中为person的表进行操作,就可以先得到以下这样一个uri对象:
Uri uri = Uri.parse("content://com.example.app.provider/person")

对到了uri对象之后我们就需要调用相应的方法对其进行操作,这样就需要借助于 ContentResolve 类, 可以通过 Context 中的 getContentResolver()方法获取到该类的实例,然后对数据进行增删改查。

以下通过两种情况进行分析:
1.获取系统应用程序的数据(以获取联系人电话方式为例)
2.本程序创建ContentProvider定义一个对外开放的接口将数据提供给其他应用程序调用。

1.获取系统应用程序的数据(以获取联系人电话方式为例)

获取系统的内容提供者的程序比较简单:
首先添加两条联系人已经电话记录:
这里写图片描述
在布局文件中增加一个ListView控件来展示获取的联系人,当然也有别的方式来显示联系人的信息,直接用TextView也可以。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <ListView           android:id="@+id/contacts_view"           android:layout_width="match_parent"           android:layout_height="match_parent" >     </ListView></RelativeLayout>

接下来给出Activity中的代码:

package com.example.androidstudycontentprovider;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.database.Cursor;import android.os.Bundle;import android.provider.ContactsContract;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.TextView;public class MainActivity extends Activity {    private ListView contactsView;    //定义一个适配器    ArrayAdapter<String> adapter;    //定义一个ArrayList数组容器来存放得到的联系人数据    List<String> contactsList = new ArrayList<String>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        contactsView = (ListView) findViewById(R.id.contacts_view);        //为适配器添加布局R.layout.simple_list_item_1(android自带的布局)以及联系人信息contactsList        adapter = new ArrayAdapter<String>(this,                android.R.layout.simple_list_item_1, contactsList);        //给ListView设置适配器        contactsView.setAdapter(adapter);        //调用readContacts()方法        readContacts();    }    private void readContacts() {        Cursor cursor = null;        try {            //查询联系人数据,ContactsContract.CommonDataKinds.Phone类已经帮我们做好了封装            //提供了一个 CONTENT_URI 常量,而这个常量就是使用 Uri.parse()方法解析出来的结果,所以可以直接就用            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容器添加需要显示的数据                contactsList.add(displayName + "  " + number);            }        } catch (Exception e) {            e.printStackTrace();        } finally {            if (cursor != null) {                //关闭cursor                cursor.close();            }        }    }}

最后在AndroidManifest.xml文件中声明可以读取联系人权限就可以了:

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

程序运行的结果如下:
这里写图片描述

2.本程序创建ContentProvider定义一个对外开放的接口将数据提供给其他应用程序调用。

对于这种情况,我们需要先掌握以下内容:
Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris ,所以我们需要先掌握下这两个类:

1.UriMatcher

UriMatcher 类主要用于匹配Uri,UriMatcher中提供了一个 addURI()方法,这个方法接收三个参数,可以分别把权限、路径和一个自定义代码传进去。这样, 当调用 UriMatcher 的 match()方法时,就可以将一个 Uri 对象传入, 返回值是某个能够匹配这个 Uri 对象所对应的自定义代码, 利用这个代码, 我们就可以判断出调用方期望访问的是哪张表中的数据了。
使用方法如下。
首先第一步,初始化:

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

第二步注册需要的Uri, 传入三个参数:

//*:表示匹配任意长度的任意字符//#:表示匹配任意长度的数字//所以,一个能够匹配任意表的内容 URI 格式就可以写成: content://com.dxy.provider/*//而一个能够匹配 table1 表中任意一行数据的内容 URI格式就可以写成: content://com.dxy.provider/table1/#//如果match()方法匹配content://com.dxy.provider/person路径,返回匹配码为PEOPLEmatcher.addURI("com.dxy.provider", "people", PEOPLE);  matcher.addURI("com.dxy.provider", "person/#", PEOPLE_ID);  

第三步,与已经注册的Uri进行匹配:

Uri uri = Uri.parse("content://" + "com.dxy.provider" + "/people");  int match = matcher.match(uri);         switch (match)         {             case PEOPLE:                 //返回值是某个能够匹配这个 Uri 对象所对应的自定义代码               return "com.dxy.provider/people";             case PEOPLE_ID:                 return "com.dxy.provider/people";             default:                 return null;         }  

2.ContentUris

ContentUris 类用于获取Uri路径后面的ID部分, 它有两个比较实用的方法:
1.withAppendedId(uri, id)用于为路径加上ID部分:

Uri uri = Uri.parse("content://com.dxy.provider");//通过withAppendedId方法,为该Uri加上ID//最后resultUri为: content://com.dxy.provider/people/10Uri resultUri = ContentUris.withAppendedId(uri, 10);  

2.parseId(uri)方法用于从路径中获取ID部分:

Uri uri = Uri.parse("content://com.dxy.provider/people/10")  //可以从路径中或者id,最后personid 为 :10long personid = ContentUris.parseId(uri);  

接下来我们看下ContentResolver类提供的四个方法对uri对象进行增删改查的操作:
1. public Uri insert(Uri uri, ContentValues values)
该方法用于往ContentProvider添加数据,用法如下:

ContentResolver resolver =  getContentResolver();Uri uri = Uri.parse("content://com.example.app.provider/person");//实例化一个ContentValues类并且插入数据,ContentValues类也是负责存储一些键值对ContentValues values = new ContentValues();values.put("name", "itcast");values.put("age", 25);resolver.insert(uri, values);

2. public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于从ContentProvider删除数据,用法如下:

ContentResolver resolver =  getContentResolver();Uri uri = Uri.parse("content://com.dxy.provider/person");//通过withAppendedId方法,为该Uri加上ID//最后deleteIdUri为: content://com.dxy.provider/people/10Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);resolver.delete(deleteIdUri, null, null);

3. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
该方法用于更新ContentProvider中的数据,用法如下:

ContentResolver resolver =  getContentResolver();Uri uri = Uri.parse("content://com.dxy.provider/person");//把id为1的记录的name字段值更改新为limingContentValues updateValues = new ContentValues();updateValues.put("name", "liming");//通过withAppendedId方法,为该Uri加上ID//最后updateIdUri为: content://com.dxy.provider/people/1Uri updateIdUri = ContentUris.withAppendedId(uri, 1);resolver.update(updateIdUri, updateValues, null, null);

4. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于从ContentProvider中获取数据.
第一个参数为Uri,代表指定查询某个应用程序下的某一张表,第二个参数指定查询的列名,第三个参数指定 where 的约束条件,第四个参数为where中的占位符提供具体的值,第五个参数指定查询结果的排序方式。

ContentResolver resolver =  getContentResolver();Uri uri = Uri.parse("content://com.dxy.provider/person");//获取person表中所有记录Cursor cursor = resolver.query(uri, null, null, null, "personid desc");while(cursor.moveToNext()){    Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1));}

具体实例代码这里不给出,可以参考android之内容提供者解析

1 0
原创粉丝点击