虽然真正做android开发也快将近一年了,但由于平时开发的内容的缘故,很多知识还是会因为没有用到而被忽略掉,所以最近重新翻回了当时的入门书籍《第一行代码》,发现有不少知识当时是看的一头雾水,现在理解能力多少有些提升了,可以再回来学习,把最基础的四大组件的知识巩固巩固。
以下笔记是我对书里的内容再加上自己的理解进行复述,因为有一种学习方法就是把学过的知识让自己以老师的身份讲出来,会让自己更好地掌握。
什么是内容提供器
首先我看了下google的文档上有一句话是“ A content provider is only required if you need to share data between multiple applications”,也就是当你需要在不同的应用上进行数据分享的时候,那么就需要用到内容提供器。
那么内容提供器的用法一般有
两种,一种是利用现有的内容提供器来读取和操作相应程序中的数据,另外一种是创建我们自己的内容提供器来提供外部访问的接口。
也就是我们用ContentProvider的两个目的,一个是我们去看别人的内容,一个是把我们的内容给别人看。
接下来就分别来看这两种:
访问其它程序中的数据
(以访问手机通讯录为例)
public class ContentProviderActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ContactAdapter contactAdapter;
private List<String> contactList = new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_provider);
initView();
initData();
}
private void initView() {
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
}
private void initData() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
100);
} else {
readContacts();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == 100) {
readContacts();
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
private void readContacts() {
Cursor cursor = null;
cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null, null);
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
));
String phone = cursor.getString(cursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER
));
contactList.add(name + " " + phone);
Log.d("ContentProvider", name + " " + phone);
}
cursor.close();
contactAdapter = new ContactAdapter(this, contactList);
recyclerView.setAdapter(contactAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL
, false));
}
}
这里面readContacts()方法里的就是我们要的内容。
那么这里要注意两个东西,一个是我们说的
ContentProvider(内容提供器)和我们现在代码里的
ContentResolver(内容解析器,通过getContentResolver()方法得到)。
所以我们可以从我们自己的角度出发 ,如果我想去看别人的数据,当我获得了这些数据后,那么我就需要去解析它,所以我需要用ContentResolver;而如果我想把我的内容提供给别人,那么我就要用ContentProvider。所以现在我们先从去看别人的数据讲起,也就是ContentResolver的使用。
ContentResolver的基本用法
首先我们可以通过Context中的getContentResolver()方法来获取ContentResolver类的实例,那么它提供了对数据进行CRUD的操作方法,分别是:insert(),update(),delete()和query()四个,那么这个跟数据库是一样的,只是参数上有存在差别。
insert(Uri url, ContentValues values)
Inserts a row into a table at the given URL.
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
Query the given URI, returning a Cursor over the result set.
update(Uri uri, ContentValues values, String where, String[] selectionArgs)
Update row(s) in a content URI.
delete(Uri url, String where, String[] selectionArgs)
Deletes row(s) specified by a content URI.
在这四个方法里我们都可以看到一个参数,就是Uri,只是它们的参数名有所不同,有的是uri,有的是url。这个大概查了下两者的区别,应该是url是从属于uri,都是对于资源的标识,但uri是属于抽象上的,相对路径的(当然也可以是绝对路径的);而url则是更为具体准确的,是绝对路径的。具体的可以看下下方的参考文章。
那么这个Uri由两部分组成:
权限+路径。
为了避免冲突,权限会以程序的包名来进行命名,假设一个程序的包名是com.example.app,那么它的权限命名是com.example.app.provider。然后这个程序里有一张表叫table1,那么这个Uri就是com.example.app.provider/table1。
最后由于标准规范的介入,我们需要加上协议声明,所以最标准的写法就是content://com.example.app.provider/table1。这样我们就知道通过这个URI字符串,我们可以访问哪个程序里的哪一张表。
当然我们这个是URI字符串,它是一个String的类型,所以我们可以通过Uri uri = Uri.parse(“content://com.example.app.provider/table1”);转换成一个URI对象,那么这个才是我们要传进去的参数。
接下来从查询方法qurey讲起,首先它返回的是一个cursor游标对象,那么也就是说我们到时是像数据库一样来利用这个游标来进行遍历查询,获取我们想要的东西。那么它所需要的参数有url,指定查询的列名,指定where的约束条件,为where中的占位符提供具体的值,还有排序方式这几个。
一旦我们通过这些条件得到了我们想要的cursor,那么就可以通过游标来取出我们要的值,如:
if (cursor!=null) {
while (cursor.moveToNext()){
String column1 = cursor.getString(cursor.getColumnIndex("column1"));
int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
}
cursor.close();
}
接下来是插入insert方法,它需要一个ContentValue的参数,ContentValue以一种键值对的形式来表达,只能存储基本数据类型,不能存储对象,这个我们只要查看它的put()方法的api就知道了。如:
ContentValues contentValues = new ContentValues();
contentValues.put("column1" , "text");
contentValues.put("column2" , 1);
getContentResolver().insert(uri , contentValues);
这里表示给列名为column1的插入一条“text”的记录,列名为“column2”的插入1的记录
update方法如下:
ContentValues contentValues = new ContentValues();
contentValues.put("column1", "");
getContentResolver().update(uri, contentValues, "column1 = ? ", new String[]{"text"});
这里表示将列名为column1里的一条名为"text“的记录给清空。 ?表示占位符,它的值就是后面的”text“。
delete方法如下:
getContentResolver().delete(uri , "column2 = ?" , new String[]{"1"});
表示将列名为column2里的那条1的记录给删除。
那么以上就是ContentResolver的基本用法。
下一篇: Android之ContentProvider跨程序共享数据入门(笔记二)
笔记来源:《第一行代码》
Android基础 : Android ContentProvider和getContentResolver