说说 Android 的内容提供器(ContentResolver )

如果一个 APP 使用内容提供器对其数据提供了对外访问的接口,那么任何其他的 APP 都可以访问这部分的数据啦,像 Android 中的电话簿、短信等程序都提供了类似的访问接口。

1 ContentResolver 基础

ContentResolver 中提供了一系列方法用于对数据进行 CRUD 操作:

方法 说明
insert() 添加数据。
update() 更新数据。
delete() 删除数据。
query() 查询数据。

这些方法使用 Uri 作为参数,它被称为内容 URI,它为数据建立了唯一标识符。内容 URI 由三部分组成:
* 协议声明 - content://
* authority - 使用程序包名来命名,用于区分不同的应用程序。
* path - 用于区分不同的表。

一个完整内容 URI 格式为:content://<authority>/<path>

得到了内容 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<String> contacts = new ArrayList<>();
    ArrayAdapter<String> 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哈哈~

猜你喜欢

转载自blog.csdn.net/deniro_li/article/details/80204436