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

Android学习(13)-跨程序共享数据

2015-01-17 10:06 295 查看
之前说到的持久化技术只能提供本程序使用,是不能分享给其他程序使用的。比如电话簿信息,短信,媒体库等。都得实现跨程序数据分享的功能。这时候就涉及到内容提供器了。

Content Provider主要用于在不同应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另外一个程序中的数据,同时保证被访问数据的安全性。

内容提供器用法有两种:

(1)利用现有的内容提供器获取其它程序里面的数据。

(2)创建自己的内容提供器,供其它程序访问我们的数据。

如果已经会使用SQLite了,那么使用ContentProvider的套路都是一样的,只是某些参数不太一样。

下面通过一个小例子说明,我们想在自己的应用中获取手机联系人信息:



首先,设计布局如下:

<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<ListView
android:id="@+id/contactslist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</ListView>

</RelativeLayout>


活动中代码如下:

public class MainActivity extends Activity {

private ListView contactList;
List<String> list = new ArrayList<String>();
ArrayAdapter<String> adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

contactList = (ListView)findViewById(R.id.contactslist);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,list);
contactList.setAdapter(adapter);
readContacts();

}

private void readContacts(){
Cursor cursor = null;
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
//第一个参数为路径,系统默认了一些路径
//路径格式为:content://com.example.app.provider/table1  协议://一般是包名/数据表名
while(cursor.moveToNext()){
//获取用户名和 手机号
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
list.add(name+"\n"+number);
}

if(cursor != null){
cursor.close();
}
}

}
获取联系人信息,也需要权限申请:

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


ok! 这样就可以获取到手机联系人信息了。 总结起来就是知道其它程序的数据访问路径,然后调用接口就ok了。

那么既然知道如何获取其它应用的数据了,如何对外暴露自身的数据呢?基于之前的SQLite项目进行修改,希望对外提供数据操作接口。

那么首先需要编写一个ContentProvider:

//对外提供内容共享接口
public class MyContentProvider extends ContentProvider {

public static final int BOOK_DIR = 0;
public static final int BOOK_ITEM = 1;
public static final int CATEGORY_DIR = 2;
public static final int CATEGORY_ITEM = 3;
//这些常量用于定义外人访问数据的类型,是访问整个表还是访问里面的某一条数据

public static final String AUTHORITY = "com.example.databasetest.provider";
//用于方法getType中,组织资源的MIME编码

public static UriMatcher uriMatcher;
//用于匹配URI的时候使用,判断别人调用数据的时候选择的是什么内容

private MyDatabaseHelper dbHelper;
//用于后续的操作数据库

static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
uriMatcher.addURI(AUTHORITY, "category", BOOK_DIR);
uriMatcher.addURI(AUTHORITY, "category/#", BOOK_DIR);
} //初始化所有的URI

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}

@Override
public String getType(Uri uri) {
//针对uri给出每一个内容的MIME编码
switch(uriMatcher.match(uri)){
case BOOK_DIR:
return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book";
//对于目录型的MIME 格式:vnd + ".android.cursor.dir" + "/vnd" + authority + "数据表名"
case BOOK_ITEM:
return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book";
//对于涉及到具体数据  其MIME编码也有一定的格式
case CATEGORY_DIR:
return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.category";
case CATEGORY_ITEM:
return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.category";
}
return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
//参数:uri  插入数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
//获取数据库操作对象
Uri uriReturn = null;
switch (uriMatcher.match(uri)) {
case BOOK_ITEM:
long newBookId = db.insert("Book", null, values);
uriReturn = Uri.parse("content://"+AUTHORITY+"/book/"+newBookId);
break;
case CATEGORY_ITEM:
long categoryId = db.insert("Category", null, values);
uriReturn = Uri.parse("content://"+AUTHORITY+"/category/"+categoryId);
break;
default:
break;
}
//从上面的代码可以看出,其实思路都非常的简单,就是先通过URI判断其他人想要干什么事情,然后通过本地的数据库操作,修改相应的数据。
//其实就是该类说自己可以对外提供数据服务,但是到了实际操作时还是依赖于数据库操作类

return uriReturn;
}

@Override
public boolean onCreate() {
//初始化的时候调用  当被那些ContentResolver访问数据时就执行该函数
dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 1);
return true;
}

@Override
public Cursor query(Uri uri, String[] columns, String selection, String[] selectionArgs,
String sortOrder) {
//数据地址   访问列  选择条件  选择数据  排序方式
return null;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

return 0;
}

}


我既然对外提供服务,那么就要在配置文件中配置信息如下:

<provider android:name="com.example.databasetest.MyContentProvider"
android:authorities="com.example.databasetest.provider"></provider>


在另外的程序中,如何消费这一个数据服务?

addBook = (Button)findViewById(R.id.addBook);
addBook.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
//明确资源路径  在哪增加数据
ContentValues values = new ContentValues();
values.put("name", "官路风流");
values.put("pages", 200);
getContentResolver().insert(uri, values);
}
});


这样就ok了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: