今天是2022年元旦,普天同庆的日子当然要记一篇CSDN庆祝下拉,又不是永远可以这么无忧无虑!
闲言少叙,直奔主题!
ContentProvider主要用于在不同的程序之间实现数据共享的功能,这是android提供了一套完整的机制,允许一个程序访问另外一个程序中的数据,同时还保证被访数据安全性。
ContentProvider用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们的程序提供外部的数据共享接口
1.我们先通过访问android系统自带的电话簿,来学习提供器如何跨程序访问数据!
任何应用,想要访问内容提供器中共享的数据,就要借助ContentResolver类,Context中的getContentResolver()可以获得实例!ContentResolver提供了一系列方法对数据进行CRUD操作,insert方法用于添加数据,update用于更新,delete用于删除,query用于查询!是不是感觉很熟悉,没错,这跟SQliteDatabase里的CRUD方法差不多,不过不同的是这些方法接收的参数不是表名,而是接收一个名为内容Uri的参数,内容Uri给内容提供器中数据建立了唯一标识符,它由两部分组成,1,权限,2,路径
权限:权限是用于对不同程序做区分,一般都采用包名的方式进行命名,譬如包名是com.shurol.app,那权限就可以命名为com.shurol.app.provider。
路径:则是对于同一程序中不同表做区分,譬如程序中有数据表table1,那路径命名为/table1
最后还需要在字符串头部加上协议声明!
所以完整的URI字符为:content://com.shurol.app.provider/table1
得到这个URI字符串后还不能直接作为参数,还需要将其解析为Uri对象,解析方法如下
Uri uri=Uri.parse("content://com.shurol.app.provider/table1");
接下来直接上代码,先直接利用内容提供器获取系统的通讯录。
public List<Preson> getData() {
List<Preson> list = new ArrayList<Preson>();//preson里只存放name,number,两个数据
Cursor cursor = null;
try {
cursor=getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
null, null);//ContactsContract.CommonDataKinds.Phone.CONTENT_URI是系统提供的访问通讯录的Uri
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(new Preson(
name,number));
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
if(cursor!=null)cursor.close();
}
return list;
}
上面这个方法就是获取系统的通讯录,把每个联系人的姓名跟电话读出来放入到准备好的存放Preson集合里!并返回集合!
接着我们创建自己的内容提供器,重新新建一个项目1,默认给新的app里用SQlite新建两张表,table1,table2,这里称项目1的应用叫APP1,我们在App1界面可以直观看到这两个数据表的信息,并且一会创建APP2来对APP1进行数据操作的时候,可以动态查看数据变化!先看我手机截图!
?我在APP1里先动态往两张数据库的表添加了这些数据,一看就知道我是文艺青年!
这两个表SQLite怎么创建表我这里就不赘述了,不了解的可以看我博客关于SQlite的用法!新建一个类命名为MyProvider,继承ContentProvider,我们主要实现这个类的六个抽象方法!先上代码,再慢慢分析!我们可以在URI路径后面再加上一个id,譬如:
content://com.shurol.app.provider/table1/1,这样代表访问table表中id为1的数据,每个方法都有注释,对数据库进行CRUD操作不熟悉的先去了解!
public class MyProvider extends ContentProvider {
private MyDatabaseHelper dbHelper;
private static UriMatcher urimatcher;
public static final int TABLE1_DIR = 0;
public static final int TABLE1_ITEM = 1;
public static final int TABLE2_DIR = 2;
public static final int TABLE2_ITEM = 3;
public static final String AUTHORITY = "com.example.contentproviderphone.provider";
/*UriMatcher类中提供了一个addURI()方法,这个方法接收三个参数,可以分别把权限,路径,和自定义的代码传进去,这样
* 当调用UriMatcher的match()方法的时候,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象的代码
* 利用这个代码,我们可以判断出调用方期望访问哪张表的数据*/
static {
urimatcher = new UriMatcher(UriMatcher.NO_MATCH);
urimatcher.addURI("com.example.contentproviderphone", "table1",
TABLE1_DIR);
urimatcher.addURI("com.example.contentproviderphone", "table1/#",
TABLE1_ITEM);
urimatcher.addURI("com.example.contentproviderphone", "table2",
TABLE2_DIR);
urimatcher.addURI("com.example.contentproviderphone", "table2/#",
TABLE2_ITEM);
}
/*Uri对象的getPathSegments()方法,他会将URI权限之后的部分按/符号进行分割,
* 把分割后的结果放入一个字符串列表中,那么0的位置就是这个Uri的路径部分,1的位置就是id了*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbHelper.getReadableDatabase();
int deleteRows = 0;
switch (urimatcher.match(uri)) {
case TABLE1_DIR:
deleteRows = db.delete("table1", selection, selectionArgs);
break;
case TABLE1_ITEM:
String table1id = uri.getPathSegments().get(1);
deleteRows = db.delete("table1", "id=?", new String[] { table1id });
break;
case TABLE2_DIR:
deleteRows = db.delete("table2", selection, selectionArgs);
break;
case TABLE2_ITEM:
String table2id = uri.getPathSegments().get(1);
deleteRows = db.delete("table2", "id=?", new String[] { table2id });
break;
default:
break;
}
return deleteRows;
}
/*这个方法必须要从提供的,用于获取Uri对象所对应的MIME类型,一个内容URI所对应的MIME字符串主要由三部分组成
* 1必须vnd开头
* 2.如果URI仪路径结尾,则后面接上android.cursor.dir/,如果是id结尾,则接上android.cursor.item/
* 3最后再接上vnd.<权限>.<路径>
* 譬如content://com.example.app.provider/table,则对应的MIME类型写成
* vnd.android.cursor.dir/vnd.com.example.app.provider.table
* 如content://com.example.app.provider/table/1则对应的MIME写成
* vnd.android.cursor.item/vnd.com.example.app.provider.table*/
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
switch (urimatcher.match(uri)) {
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.contentproviderphone.provider.table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.contentproviderphone.provider.table1";
case TABLE2_DIR:
return "vnd.android.cursor.dir/vnd.com.example.contentproviderphone.provider.table2";
case TABLE2_ITEM:
return "vnd.android.cursor.item/vnd.com.example.contentproviderphone.provider.table2";
default:
break;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues value) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbHelper.getWritableDatabase();
Uri uriReturn = null;
switch (urimatcher.match(uri)) {
case TABLE1_DIR:
case TABLE1_ITEM:
long newid = db.insert("table1", null, value);
uriReturn = Uri.parse("content://" + AUTHORITY + "/table1/" + newid);
break;
case TABLE2_DIR:
case TABLE2_ITEM:
long newid2 = db.insert("table2", null, value);
uriReturn = Uri.parse("content://" + AUTHORITY + "/table2/" + newid2);
break;
default:
break;
}
return uriReturn;
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
dbHelper = new MyDatabaseHelper(getContext(), "MyStore.db", null, 2);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor curson = null;
switch (urimatcher.match(uri)) {
case TABLE1_DIR:
curson = db.query("table1", projection, selection, selectionArgs,
null, null, sortOrder);
break;
case TABLE1_ITEM:
String tableID = uri.getPathSegments().get(1);
Log.d("data", tableID);
curson = db.query("table1", projection, "id=?",
new String[] { tableID }, null, null, sortOrder);
break;
case TABLE2_DIR:
curson = db.query("table2", projection, selection, selectionArgs,
null, null, sortOrder);
break;
case TABLE2_ITEM:
String table2ID = uri.getPathSegments().get(1);
curson = db.query("table2", projection, "id=?",
new String[] { table2ID }, null, null, sortOrder);
break;
default:
break;
}
return curson;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbHelper.getReadableDatabase();
int updatedRow = 0;
switch (urimatcher.match(uri)) {
case TABLE1_DIR:
updatedRow = db.update("table1", values, selection, selectionArgs);
break;
case TABLE1_ITEM:
String tableID = uri.getPathSegments().get(1);
updatedRow = db.update("table1", values, "id=?",
new String[] { tableID });
break;
case TABLE2_DIR:
updatedRow = db.update("table2", values, selection, selectionArgs);
break;
case TABLE2_ITEM:
String table2ID = uri.getPathSegments().get(1);
updatedRow = db.update("table2", values, "id=?",
new String[] { table2ID });
break;
default:
break;
}
return updatedRow;
}
}
?到这里,APP1里的所有代码就完成了,接着新建APP2的程序,简单用内容提供器的方法访问和操作APP1提供好的数据!
上APP2代码
public class MainActivity extends Activity implements OnClickListener {
Button bt_insert, bt_update, bt_select, bt_delete;
TextView tv_table1, tv_table2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
bt_insert = (Button) findViewById(R.id.bt_insert);
bt_update = (Button) findViewById(R.id.bt_update);
bt_select = (Button) findViewById(R.id.bt_showdata);
bt_delete = (Button) findViewById(R.id.bt_delete);
tv_table1 = (TextView) findViewById(R.id.tv_table1);
tv_table2 = (TextView) findViewById(R.id.tv_table2);
bt_insert.setOnClickListener(this);
bt_update.setOnClickListener(this);
bt_select.setOnClickListener(this);
bt_delete.setOnClickListener(this);
}
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
switch (view.getId()) {
case R.id.bt_insert:
// 添加数据
Uri uri = Uri
.parse("content://com.example.contentproviderphone.provider/table1");
ContentValues values = new ContentValues();
values.put("name", "三国演义");
values.put("author", "罗贯中");
values.put("pages", 254);
values.put("price", 22.34);
getContentResolver().insert(uri, values);
break;
case R.id.bt_update:
Uri uri2 = Uri
.parse("content://com.example.contentproviderphone.provider/table2/2");
ContentValues valuse2 = new ContentValues();
valuse2.put("price", 100.00);
getContentResolver().update(uri2, valuse2, null, null);
break;
case R.id.bt_delete:
Uri uri3 = Uri.parse("content://com.example.contentproviderphone.provider/table1/1");
getContentResolver().delete(uri3, null, null);
break;
case R.id.bt_showdata:
StringBuffer sb = new StringBuffer();
Uri uri4 = Uri
.parse("content://com.example.contentproviderphone.provider/table1");
Cursor cursor = getContentResolver().query(uri4, null, null, null,
null);
while (cursor.moveToNext()) {
sb.append(cursor.getString(cursor.getColumnIndex("name")) + ","
+ cursor.getString(cursor.getColumnIndex("name")) + ","
+ cursor.getInt(cursor.getColumnIndex("pages")) + ","
+ cursor.getDouble(cursor.getColumnIndex("price"))
+ "\n");
tv_table1.setText(sb.toString());
}
break;
default:
break;
}
}
APP2界面有四个按钮,还有两个TextView,用来展示table1,table2里的数据。好了,代码相信很简单,一看就懂,一学就废!我自己已经扛不住了,脖子好酸!程序员的悲哀!
|