Android中的四大组件有一个叫做ContentProvider的东西,这货是用来干什么的呢?
下面听小弟给你细细道来:
基本介绍:
Android中有四大组件分别是Activity,ContentProvider,Service,BroadcastReceiver,它们都需要在AndroidManifest.xml文件中进行配置.
ContentProvider组件主要用于Android系统中应用程序之间交换数据,当一个应用程序需要把自己的数据暴露给其他程序使用时,该应用程序就可以通过ContentProvider来实现;其他应用程序就可以通过ContentResolver来操作ContentProvider暴露的数据.
当一个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程序是否启动,其他应用程序都可以通过该接口操作该应用程序内部的数据,包括增加,删除,修改,查询数据等.
大概思路:
ContentProvider以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentResolver根据Uri去访问操作指定数据;
开发ContentProvider步骤:
1.定义自己的ContentProvider类,该类需要继承Android提供的ContentProvider基类.
2.向Android系统注册这个ContentProvider,也就是在AndroidManifest.xml文件中注册这个ContentProvider,就和注册Activity一样,注册ContentProvider时需要为它绑定一个Uri;
注:向Android中注册ContentProvider,只需在AndroidManifest.xml配置文件中<application.../>元素下添加如下子元素即可:
<!- -下面配置中name属性指定为ContentProvider类,
authorities就相当于为该ContentProvider指定域名,exported设置为true就是允许其他应用访问该应用内部
- ->
<provider
android:name="com.xiyou.MProvider"
android:authorities="com.xiyou.provider.mprovider"
android:exported="true"/>
通过注册上面的provider别的应用就可以通过这个Uri访问MProvider所暴露的数据.
继承ContentProvider的这个MProvider类通常要提供以下几种方法,以让外部应用访问:
public boolean onCreate():该方法在ContentProvider创建后会被调用,当其他应用程序第一次访问ContentProvider,该ContentProvider会被创建出来,并立即回调该onCreate()方法.
public Uri insert(Uri uri, ContentValues values):根据该Uri插入values对应的数据.
public int delete(Uri uri, String selection, String[] selectionArgs):根据Uri删除select条件所匹配的全部数据.
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):根据Uri修改select条件所匹配的全部记录.
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):根据Uri查询出select条件所匹配的全部记录,其中projection就是一个列名列表,表明只选择出指定的数据列.
public String getType(Uri uri):该方法用于返回当前Uri所代表的数据的MIME类型.如果该Uri对应数据可能包括多条记录,那么MIME类型字符串应该以vnd.android.cursor.dir/开头;如果该Uri对应的数据只包含一条记录,那么返回MIME类型字符串应该以vnd.android.cursor.item/开头.
从每一个方法的参数中我们可以看出Uri是一个非常重要的参数,那么下面我们来了解了解Uri:
我们先来给出一个简单的URL:http://www.xiyou.edu.cn/test.php
分解开来看:
http://:URL的协议部分;只要通过HTTP协议访问网站,这个部分是固定的.
www.xiyou.edu.cn:域名部分.只要访问指定的网站,这个部分总是固定的.
test.php:网站资源部分.当访问者需要访问不同资源时,这个部分根据资源的不同而改变.
ContentProvider要求的Uri与此类似,例如如下Uri:content://com.xiyou.provider.mprovider/test
分解开来看:
content://:此部分是Android的ContentProvider规定的,就想网上的协议默认是http://一样.暴露ContentProvider,访问ContentProvider的协议默认是content://.
com.xiyou.provider.mprovider:这个部分是就是ContentProvider的authority.系统就是由这个部分来找到操作哪个ContentProvider只要访问指定的ContentProvider,这个部分总是固定的.
test:资源部分,当访问者需要访问不同的资源时,这个部分是动态改变的
使用ContentResolver操作数据如下方法:
通过getContentResolver()方法获取ContentResolver对象,获得ContentResolver对象后通过调用ContentResolver的如下方法操作ContentProvider中的数据.
insert(Uri uri, ContentValues values):向对应的ContentProvider中插入values对应的数据.
delete(Uri uri, String where, String[] selectionArgs):删除Uri对应的ContentProvider中where提交匹配的数据.
update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri对应的ContentProvider中where提交匹配的数据.
query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder):查询Uri对应的ContentProvider中select提交的匹配的数据.
ContentProvider,Uri,COntentResolver三者之间有着某些关系:
下面开发一个ContentProvider和ContentResolver的例子来给大家看看:
ContentProvider程序:
package com.example.firstprovider;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.view.Menu;
public class MainActivity extends ContentProvider {
// 第一次创建该ContentProvider时调用该方法
@Override
public boolean onCreate() {
System.out.println("==onCreate()方法被调用==");
return true;
}
// 实现查询方法,该方法应该返回查询得到的Cursor
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
System.out.println(uri + "==query()方法被调用==");
System.out.println("selection参数为:" + selection);
return null;
}
// 该方法的返回值代表了该ContentProvider所提供的数据的MIME类型.
@Override
public String getType(Uri uri) {
return null;
}
// 实现插入的方法,该方法应该返回新插入的记录的Uri
@Override
public Uri insert(Uri uri, ContentValues values) {
System.out.println(uri + "==insert()方法被调用==");
System.out.println("values参数为:" + values);
return null;
}
// 实现删除方法,该方法应该返回被更新的记录条数
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
System.out.println(uri + "==deletet()方法被调用==");
System.out.println("selection参数为:" + selection);
return 0;
}
// 实现更新方法,该方法应该返回被更新的记录条数
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
System.out.println(uri + "==update()方法被调用==");
System.out
.println("selection参数为:" + selection + ",values参数为:" + values);
return 0;
}
}
ContentProvider程序的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.firstprovider"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.firstprovider.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name=".MainActivity"
android:authorities="com.xiyou.provider.firstprovider"
android:exported="true"
></provider>
</application>
</manifest>
ContentResolver程序:
布局代码中只有四个button所以未给出:
package com.example.firstresolver;
import android.net.Uri;
import android.os.Bundle;
import android.R.integer;
import android.app.Activity;
import android.app.DownloadManager.Query;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
Button query, insert, update, delete;
Uri uri = Uri.parse("content://com.xiyou.provider.firstprovider/");
ContentResolver contentResolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contentResolver = this.getContentResolver();
query = (Button) findViewById(R.id.query);
update = (Button) findViewById(R.id.update);
insert = (Button) findViewById(R.id.insert);
delete = (Button) findViewById(R.id.delete);
query.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
query(v);
}
});
insert.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
insert(v);
}
});
delete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
delete(v);
}
});
update.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
update(v);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void query(View source) {
// 调用ContentResolver的query()方法
// 实际返回的是该Uri对应的ContentProvider的query()的返回值
Cursor c = contentResolver.query(uri, null, "query_where", null, null);
Toast.makeText(this, "远程ContentProvider返回的Cursor为:" + c,
Toast.LENGTH_SHORT).show();
}
public void insert(View source) {
ContentValues contentValues = new ContentValues();
contentValues.put("name", "xiyoucx");
// 调用ContentResolver的insert()方法
// 实际返回的是该Uri对应ContentProvider的insert()方法返回值
Uri newUri = contentResolver.insert(uri, contentValues);
Toast.makeText(this, "远程ContentProvider返回的新插入记录的Uri为:" + newUri,
Toast.LENGTH_SHORT).show();
}
public void update(View source) {
ContentValues contentValues = new ContentValues();
contentValues.put("name", "xiyoucx");
// 调用ContentResolver的update()方法
// 实际返回的是该Uri对应的contentp的update()返回值
int count = contentResolver.update(uri, contentValues, "update_values",
null);
Toast.makeText(this, "远程ContentProvider返回的新插入记录数为:" + count,
Toast.LENGTH_SHORT).show();
}
public void delete(View source) {
// 调用ContentResolver的delete()方法
// 实际返回的是该Uri对应的contentp的delete()的返回值
int count = contentResolver.delete(uri, "delete_where", null);
Toast.makeText(this, "远程ContentProvider返回的删除记录数为:" + count,
Toast.LENGTH_SHORT).show();
}
}
运行结果:
这奏是两个程序之间的数据交换.
下面我们再来看看应用程序如何获取系统内部数据:
以联系人为例:
未完待续~~