说说 Android(安卓)的内容提供器(ContentResolver )
如果一个 APP 使用内容提供器对其数据提供了对外访问的接口,那么任何其他的 APP 都可以访问这部分的数据啦,像 Android 中的电话簿、短信等程序都提供了类似的访问接口。
1 ContentResolver 基础
ContentResolver 中提供了一系列方法用于对数据进行 CRUD 操作:
方法 | 说明 |
---|---|
insert() | 添加数据。 |
update() | 更新数据。 |
delete() | 删除数据。 |
query() | 查询数据。 |
这些方法使用 Uri 作为参数,它被称为内容 URI,它为数据建立了唯一标识符。内容 URI 由三部分组成:
* 协议声明 - content://
* authority - 使用程序包名来命名,用于区分不同的应用程序。
* path - 用于区分不同的表。
一个完整内容 URI 格式为:content:///
得到了内容 URI 字符串后,需要调用 Uri.parse() 方法把它解析为 Uri 对象就可以作为参数传入 ContentResolver 方法,代码如下:
Uri uri = Uri.parse("content://com.deniro.app.provider/tableName");Cursor cursor = getContentResolver().query(uri,projection,selection,selectionArgs,sortOrder);
1.1 查询
query 方法参数说明:
参数 | 说明 | 示例 |
---|---|---|
uri | 查询某个 APP 下的某一张表 | from table_name |
projection | 指定表列名 | select column1,column2 |
selection | 指定 where 约束条件 | where column = value |
selectionArgs | 为 selection 中的占位符提供具体的值 | - |
orderBy | 指定排序方式 | order by column1,column2 |
查询完成后会返回一个 Cursor 对象,读取逻辑是:通过移动游标来遍历 Cursor 中的所有行,然后再取出每一行中相应列的数据,代码如下:
if (cursor != null){ while (cursor.moveToNext()){ String column1 = cursor.getString(cursor.getColumnIndex("column1")); int column2 = cursor.getInt(cursor.getColumnIndex("column2")); ... } cursor.close();}
1.2 新增
insert 方法定义如下:
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url, @Nullable ContentValues values)
它还需要一个 ContentValues,作为需要新增的数据。
示例代码如下:
ContentValues values = new ContentValues();values.put("column1","data");values.put("column2",1);getContentResolver().insert(uri, values);
1.3 更新
update 方法定义如下:
public final int update(@RequiresPermission.Write @NonNull Uri uri, @Nullable ContentValues values, @Nullable String where, @Nullable String[] selectionArgs)
除了 uri 与 ContentValues ,update 方法还需要 where 条件约束的参数,来确定需要更新的数据范围。
示例代码如下:
ContentValues values = new ContentValues();values.put("column1","new_data");getContentResolver().update(uri, values, "column1 = ? and column2 = ?",new String[]{"data","1"});
1.4 删除
delete 方法定义如下:
public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where, @Nullable String[] selectionArgs)
delete 方法所需要的参数与 update 方法相同。
示例代码如下:
getContentResolver().delete(uri, "column1 = ?", new String[]{"data"});
2 读取系统联系人信息
首先在模拟器中手工添加一些联系人信息,打开电话簿,点击 【ADD A CONTACT 】或者右下角的图标按钮:
第一次新增联系人时,会弹出【是否创建在线账号用于备份联系人信息】的选择框,这里我们选择 KEEP LOCAL:
然后输入联系人的姓名与手机号码:
接着,点击右上角的打勾按钮。
最后,以类似的方式再添加一个联系人:
现在,我们要开始使用内容提供器来读取系统联系人信息啦。
布局文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" 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="net.deniro.android.contactstest.MainActivity"> <ListView android:id="@+id/contacts" android:layout_width="match_parent" android:layout_height="match_parent">ListView>LinearLayout>
我们把读取到的系统联系人信息放在一个 ListView 中展示。
Activity:
package net.deniro.android.contactstest;import android.Manifest;import android.content.pm.PackageManager;import android.database.Cursor;import android.os.Bundle;import android.provider.ContactsContract;import android.support.annotation.NonNull;import android.support.v4.app.ActivityCompat;import android.support.v4.content.ContextCompat;import android.support.v7.app.AppCompatActivity;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity { List contacts = new ArrayList<>(); ArrayAdapter adapter = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //设置 ListView 内容 ListView contactsView = (ListView) findViewById(R.id.contacts); adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, contacts); contactsView.setAdapter(adapter); if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { //请求读取联系人的权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1); } else { readContacts(); } } private void readContacts() { Cursor cursor = null; try { cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { //联系人姓名 String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); //手机号 String mobile = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); contacts.add(name + ":" + mobile); } //通知 ListView 数据已更新 adapter.notifyDataSetChanged(); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 1://获得权限后,读取联系人 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { readContacts(); } else { Toast.makeText(this, "被拒绝", Toast.LENGTH_SHORT).show(); } break; default: throw new RuntimeException("onRequestPermissionsResult"); } }}
这里使用了 ContentResolver 的 query() 方法来查询系统联系人的数据。ContactsContract.CommonDataKinds.Phone.CONTENT_URI
封装了内容 URI 字符串;接着,从 ContactsContract.CommonDataKinds.Phone
常量中,通过 Cursor 对象遍历获取联系人的姓名与手机号;然后通知 ListView 刷新列表。
因为读取系统联系人涉及到危险权限,所以这里先判断是否有权限。
最后记得在 AndroidManifest.xml 中声明权限:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
为了示例的简洁,没有即时刷新联系人列表,所以如果有新增联系人,需要退出 APP 后再进入才会刷新联系人列表。
运行 APP:
是不是很简单呀O(∩_∩)O哈哈~
更多相关文章
- Android(安卓)中 startService()启动service的过程分析
- Android常用的数据结构
- Android(安卓)蓝牙BLE开发详解
- Android(安卓)Tab切换之Fragment方法
- Android视图绘制流程解析(二)
- Android(安卓)MediaPlayer和VideoView的使用
- Android退出整个应用的方法
- android第一次启动时Settings的默认值
- Android(安卓)ADB超简单的安装教程(推荐)