在Android中,每一个应用程序的数据都是采取私有的形式进行操作,不管这些数据是用文件还是数据库保存,都不能被外部应用程序所访问。但是咋很多情况下,用户需要可以在不同的应用程序之间进行交换的数据,所以为了解决这个问题,在Android中专门提供了一个ContentProvider类,此类的主要功能是将不同的应用程序的数据操作标准统一起来,并且将各个应用程序的数据操作标准表明给其他应用程序,这样,一个应用程序的数据就可以按照ContentProvider所定制的标准被外部所操作。
ContentProvider在程序操作中所提供的是一个操作标准,所以如果要想依靠此标准进行数据操作,必须使用ContentResolver类来完成,而该类中所给出的操作方法与ContentProvider是一一对应的,当用户调用ContentResolver类的方法是,实际上就是相当于用了ContentProvider类中的方法。具体操作关系如下图:
注:关于ContentProvider/ContentResolver的理解:前者提供了对SQLite的一些操作的标准化封装,如同为SQLite制作好了一把锁,后者就是开这把锁的药匙,以后程序中任何有关SQLite的操作,都必须先实例化ContentResolver对象,取得ContentResolver,再使用UriMatcher匹配成功uri,之后就可以进行有关的insert、delete、update等操作。
由于这次涉及的代码量有点多,下面就逐个讲解重点部分,首先声明一个DatabaseMateData借口类,里面封装了有关操作的元数据,有外部访问链接,数据库名称,数据库版本,数据表名称,数据库字段等,具体java文件如下:
package cn.norysn.contentproviderdemo;
import android.net.Uri;
import android.provider.BaseColumns;
public interface DatabaseMetaData {
//外部发访问Authroity
public static final String AUTHROITY = "cn.norysn.membercontentprovider";
//public static final String AUTHROITY = "cn.norysn.contentproviderdemo";
//定义数据库名称
public static final String DATABASE_NAME = "norysn.db";
//数据库版本
public static int VERSION = 1;
//member表的元数据定义
public static interface MemberTableMetaData extends BaseColumns{
//数据表名称
public static final String TABLE_NAME = "member";
//外部访问URI地址
public static final Uri CONTENT_URI = Uri.parse("content://"
+AUTHROITY+"/"+TABLE_NAME);
//取得memeber表中的所有数据
public static final String CONTENT_LIST = "vnd.android.cursor.dir/vnd.contentproviderdemo.member";
//按ID查询
public static final String CONTENT_ITEM = "vnd.android.cursor.item/vnd.contentproviderdemo.member";
//member字段名称
public static final String MEMBER_NAME = "name";
public static final String MEMBER_AGE = "age";
public static final String MEMBER_BIRTHDAY = "birthday";
public static final String SORT_ORDER = "_id DESC";
}
}
定义了数据库操作的助手类,MyDatabaseHelper.java,这个类的功能与之前章节中介绍的一样,主要是用来创建数据库,数据表,源码如下:
package cn.norysn.contentproviderdemo;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDatabaseHelper extends SQLiteOpenHelper {
//数据库名称
private static final String DATABASE_NAEM = "norysn.db";
//版本号
private static final int DATABASE_VERSION = 1;
//数据表名称
private static final String TABLE_NAME = "member";
public MyDatabaseHelper(Context context) {
//构造父类
super(context, DATABASE_NAEM, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//sql语句
String sql = "create table "+TABLE_NAME+" ("
+DatabaseMetaData.MemberTableMetaData._ID
+" integer primary key ,"
+DatabaseMetaData.MemberTableMetaData.MEMBER_NAME
+" varchar(20) not null ,"
+DatabaseMetaData.MemberTableMetaData.MEMBER_AGE
+" integer not null ,"
+DatabaseMetaData.MemberTableMetaData.MEMBER_BIRTHDAY
+" date not null)";
//执行SQL语句
db.execSQL(sql);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String sql = "drop table if exists "+TABLE_NAME;
db.execSQL(sql);
this.onCreate(db);
}
}
接着定义member表操作的MemberContentProvider类,该类必须继承ContentProvider类,并且在类中覆写抽象方法,本例子中只是在oncreate(),insert(),query()中做了相应的代码添加,代码如下:
package cn.norysn.contentproviderdemo;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
public class MemberContentProvider extends ContentProvider {
//定义UriMatcher对象
private static UriMatcher uriMatcher = null;
//定义常量标记
private static final int GET_MEMBER_LIST = 1;
private static final int GET_MEMBER_ITEM = 2;
private MyDatabaseHelper helper = null;
static{
//实例化UriMatcher
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//增加匹配URI
uriMatcher.addURI(DatabaseMetaData.AUTHROITY, "member", GET_MEMBER_LIST);
uriMatcher.addURI(DatabaseMetaData.AUTHROITY, "member/#", GET_MEMBER_ITEM);
}
@Override
public boolean onCreate() {
this.helper = new MyDatabaseHelper(super.getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
//SQLiteDatabase db = this.helper.getWritableDatabase();
SQLiteDatabase db = this.helper.getReadableDatabase();
switch(uriMatcher.match(uri)){
case GET_MEMBER_LIST:
//查询操作
return db.query(DatabaseMetaData.MemberTableMetaData.TABLE_NAME,
projection, selection, selectionArgs, null, null, sortOrder);
case GET_MEMBER_ITEM:
long id = ContentUris.parseId(uri);
String where = "_id="+id;
return db.query(DatabaseMetaData.MemberTableMetaData.TABLE_NAME,
projection, where, selectionArgs, null, null, sortOrder);
default:
//抛出异常
throw new UnsupportedOperationException("Not Support query Operation:"+uri);
}
}
@Override
public String getType(Uri uri) {
//match()指定URI位置
switch(uriMatcher.match(uri)){
case GET_MEMBER_LIST:
return DatabaseMetaData.MemberTableMetaData.CONTENT_LIST;
case GET_MEMBER_ITEM:
return DatabaseMetaData.MemberTableMetaData.CONTENT_ITEM;
default:
throw new UnsupportedOperationException("Not Support Operation: "+uri);//抛出异常
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = helper.getWritableDatabase();//取得数据库对象
long id = 0;
switch(uriMatcher.match(uri)){
case GET_MEMBER_LIST:
id = db.insert(DatabaseMetaData.MemberTableMetaData.TABLE_NAME,
DatabaseMetaData.MemberTableMetaData._ID, values);
return ContentUris.withAppendedId(uri, id);
case GET_MEMBER_ITEM:
id = db.insert(DatabaseMetaData.MemberTableMetaData.TABLE_NAME,
DatabaseMetaData.MemberTableMetaData._ID, values);
String uriPath = uri.toString();
String path = uriPath.substring(0,uriPath.lastIndexOf("/"))+id;
return Uri.parse(path);
default:
throw new UnsupportedOperationException("Not Support insert Opetarion:"+uri);
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
}
最后就是主Activity(MyContentProviderDemo)操作了,当按下增加按钮时,完成数据库、数据表的创建,并使用Toast提示,当按下查询按钮之后,使用ListView控件,自定义布局member.xml文件显示查询结果。
package cn.norysn.contentproviderdemo;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
public class ContentProviderDemo extends Activity {
//定义组件
private Button insertBtn = null;
private Button queryBtn = null;
private TextView showInfo = null;
private ListView membersList = null;
public long testInsert(String name, int age, String birthday) throws Exception{
ContentResolver contentResolver = null;
contentResolver = getContentResolver();//获取ContentResolver
ContentValues values = new ContentValues();//设置内容
values.put(DatabaseMetaData.MemberTableMetaData.MEMBER_NAME, name);
values.put(DatabaseMetaData.MemberTableMetaData.MEMBER_AGE, age);
values.put(DatabaseMetaData.MemberTableMetaData.MEMBER_BIRTHDAY, birthday);
//执行增加操作
Uri resultUri = contentResolver.insert(DatabaseMetaData.MemberTableMetaData.CONTENT_URI, values);
return ContentUris.parseId(resultUri);
}
public Cursor testQuery(String id) throws Exception{
//查询全部
if(id==null || "".equals(id)){
return super.getContentResolver().query(DatabaseMetaData.MemberTableMetaData.CONTENT_URI,
null,null, null, DatabaseMetaData.MemberTableMetaData.SORT_ORDER);
}else{
//根据ID查询
return super.getContentResolver().query(Uri.withAppendedPath(DatabaseMetaData.MemberTableMetaData.CONTENT_URI,id),
null, null, null, DatabaseMetaData.MemberTableMetaData.SORT_ORDER);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//获得组件ID
insertBtn = (Button)findViewById(R.id.insertBtn);
queryBtn = (Button)findViewById(R.id.queryBtn);
showInfo = (TextView)findViewById(R.id.showinfo);
membersList = (ListView)findViewById(R.id.membersList);
//设置监听事件
insertBtn.setOnClickListener(new insertBtnListener());
queryBtn.setOnClickListener(new queryBtnListener());
}
public class insertBtnListener implements OnClickListener{
public void onClick(View v) {
showInfo.setText("执行的是增加操作...");
long id = 0;
try {
id = ContentProviderDemo.this.testInsert("luhua", 26,
new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(ContentProviderDemo.this, "数据增加成功,ID为:"+id, Toast.LENGTH_LONG).show();
}
}
//query operate
public class queryBtnListener implements OnClickListener{
@SuppressWarnings("deprecation")
public void onClick(View v) {
showInfo.setText("执行的是查询操作...");
Cursor result = null;
try {
result = ContentProviderDemo.this.testQuery(null);
} catch (Exception e) {
e.printStackTrace();
}
//System.out.println(result.getInt(0));
if(result != null){
System.out.println("result is not null");
}else{
System.out.println("result is null");
}
//Cursor交由系统管理
ContentProviderDemo.this.startManagingCursor(result);
List<Map<String, Object>> members = null;
members = new ArrayList<Map<String, Object>>();
for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){
Map<String, Object> member = new HashMap<String, Object>();
member.put("_id", result.getInt(0));
member.put("name", result.getString(1));
member.put("age", result.getInt(2));
member.put("birthday", result.getString(3));
members.add(member);//保存Map中
}
//ContentProviderDemo.this.stopManagingCursor(result);
//适配器
ContentProviderDemo.this.membersList.setAdapter(new SimpleAdapter(ContentProviderDemo.this,
members,
R.layout.member,
new String[]{"_id", "name", "age", "birthday"},
new int[]{R.id._id, R.id.name, R.id.age, R.id.birthday}));//显示数据
Toast.makeText(ContentProviderDemo.this, "数据查询成功,ID为:", Toast.LENGTH_LONG).show();
}
}
}
修改AndroidManifest.xml文件,配置ContentProvider权限:
<provider
android:name=".MemberContentProvider"
android:authorities="cn.norysn.membercontentprovider"></provider>
android:authorities属性与DatabaseMetaData接口中配置的AUTHORITY全局常量一致,以后访问此ContentProvider程序的Uri的组成部分。
查询效果截图:
源码下载 密码:j3fe