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

Android笔记之Content Provider(内容提供器)

2016-05-09 05:11 513 查看
Content Provider:内容提供器。

用于在不同的程序之间实现数据共享的功能,不仅能允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据。另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口。

当一个程序通过内容提供器对其数据提供了外部访问接口,任何其他的应用程序都可以对这部分数据进行访问。Android系统中自带的电话簿短信媒体库等程序都提供了类似的访问接口。

ContentResolver类:对于每一个程序来说,如果想要访问内容提供器中共享的数据,就一定要借助ContentResolver类,可以通过Context中的getContentResolver()方法获取到该类的实例。ContentResolver中提供了一系列的方法用于对数据进行CRUD(增删改查)操作。和SQLiteDatabase的四个方法名相同,操作数据的方法都是一样的,只是在参数接收上有一些细微的区别。

不同于SQLiteDatabase,ContentResolver中的增删改查方法都是不接收表名参数,而是使用一个Uri参数代替,这个参数被称为内容URI。内容URI给内容提供器中的数据简历了唯一标识符,它主要由两部分组成,权限和路径。

内容URI的标准格式写法如下:

content://com.example.app.provider/1

content://com.example.app.provider/2

得到了内容URI字符串后,还需要将它解析成Uri对象才可以作为参数传入(系统内置的不需要解析,因为他本身就是一个URI),比如:

Uri uri=Uri.parse("content://com.example.app.provider/1")

调用Uri.parse()方法,就可以将内容URI字符串解析成Uri对象。

使用Uri对象来查询表中的数据:

Cursor cursor=getContentResolver().query(uri,projection,selection,selectionArgs,sorOrder);

ContentResolver对象的query()查询方法接收五个参数,第一个参数指定查询某个应用程序下的某张表。第二个参数指定查询的列名,第三个参数指定where的约束条件,第四个参数为where中的占位符提供具体的值,第五个参数指定查询结果的排序方式。

同时query()方法完成后返回的仍然是一个Cursor对象。这时就可以将数据从Cursor对象中读取出来。读取思路依旧是通过移动游标的位置来遍历Cursor中的所有行,然后再取出每一行中相应列的数据。

示例代码:

if (cursor!=null){
//查询得到的cursor是指向第一条记录之前的,因此查询得到cursor后第一次调用moveToFirst或moveToNext都可以将cursor移动到第一条记录.
while(cursor.moveToNext()){
String column1=corsor.getString(cursor.getColumnIndex("column1"));
int column2=cursor.getInt(cursor.getColumnIndex("column2"));
}
cursor.close();
}


获取系统电话簿中的联系人信息。

示例代码:

先是布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>

</LinearLayout>
只是添加了一个ListView控件。

然后是MainActivity中的java代码:

public class MainActivity extends AppCompatActivity {
ListView contactsView;
ArrayAdapter<String> adapter;
//创建ArrayList数组,数据类型为String。
List<String> contactsList=new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

//获取ListView控件实例。
contactsView=(ListView)findViewById(R.id.listView);
//创建ArrayAdapter适配器实例,依次在构造函数中传入三个参数,当前上下文,子项布局id(这里还是选择Android内置的布局文件),以及要适配的数据。
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{
//查询联系人数据,需要查询所有的数据,因此后面四个约束参数都填入null。
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));
//将获取到的姓名和号码存储到数组当中,由于数组已经存储于适配器中并与ListView进行了关联,这样就能在界面中展示出来了。
contactsList.add(displayName+"\n"+number);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭cursor。
if (cursor!=null){
cursor.close();
}
}
}
}
在readContacts()方法中,使用了ContentResolver对象的query()方法来查询系统联系人的数据,不过传入的Uri参数并没有调用Uri.parse()方法去解析一个内容URI字符串,是因为ContactsContract.CommonDataKinds.Phone类已经做好了封装,提供了一个CONTENT_URI常量。这个常量本身就是使用Uri.parse()方法解析出来的结果。接着对Cursor对象进行遍历,将联系人姓名和手机号这些数据逐个取出,联系人姓名和手机号对应的常量分别是ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME和ontactsContract.CommonDataKinds.Phone.NUMBER,两个数据都取出之后将他们进行拼接,在中间加上换行符,然后将拼接后的数据添加到ListView里。

因为读取系统联系人是需要声明权限的,代码如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tangyi.contactstest">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

</application>
<!--声明读取系统联系人权限。-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>

</manifest>
以上就是获取系统联系人的代码,只不过内容URI字符串是系统提供的。

上面已经说过,想要实现跨程序共享数据的功能,就是使用内容提供器,可以通过新建一个类去继承ContentResolver类的方式来创建一个自己的内容提供器,ContentResolver类中提供了六个抽象方法,在使用子类继承它的时候,需要将这六个方法全部重写。代码如下所示:

public class MyProvider extends ContentProvider {

//onCreate()方法,初始化内容提供器时调用,通常在这个方法中完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则失败。注意:只有当存在ContentResolver尝试访问程序中的数据时,内容提供器才会被初始化。
@Override
public boolean onCreate() {
return false;
}

//query()方法,从内容提供器中查询数据。使用uri参数来确定查询哪张表,projection参数用于查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}

//insert()方法,向内容提供器中添加一条数据,使用uri参数来确定要添加的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新纪录的URI。
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}

//update()方法,更新内容提供器中已有的数据。使用uri参数来确定更新哪一张表中的数据,新数据保存在values参数中。selection和selectionArgs参数用于约束更新哪些行,受影响的行数作为返回值返回。
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}

//delete()方法,从内容提供器中删除数据。使用uri参数来确定删除哪一张表中的数据,selection和selectionArgs参数用于约束删除哪些行,被删除的行数作为返回值返回。
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}

//getType()方法,根据传入的内容URI来返回相应MIME类型。
@Override
public String getType(Uri uri) {
return null;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: