【Android】20.0 权限处理(二)——访问其他程序数据:读取联系人信息

1.0 在我的上一篇,相当于运行时权限的初体验,这一篇主要是怎么访问其他程序的数据,比如接下来的这个例子,将手机联系人应用中的联系人数据,读取出来,在APP中展示。
2.0 一个应用程序通过内容提供器可以对其数据提供外部访问接口,其他任何应用程序都可以对这部分数据进行访问。

Android系统自带的电话簿、短信、媒体库等程序都提供了类似的访问接口,这使得第三方应用程序可以充分地利用这部分数据来实现更好的功能。

3.0对于每一个应用程序来说,如果想访问内容提供器中共享的数据,就一定要借助ContentResolver类,可以通过Context中的getContentResolve方法获得该类的实例。

ContentResolver中提供了一系列的方法用于增删查改操作。不错,和SQLiteDatabase很相似。

不同于SQLiteDatabase,ContentResolver使用的是内容URI参数。
标准格式为:
content://com.example.app.provider/table1
content://com.example.app.provider/table2

内容URI主要由2部分组成:authority和path

  • authority:用于对不同应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来命名。
    比如某个程序包名为com.example.app,该程序的authority就可以命名为com.example.app.provider

  • path:用于对同一应用程序中不同的表做以区分,通常添加在authority后面。

4.0 闲话放最后说,先上车直接干代码,新建项目ContactsTest,目录如下:
16102290-abdd1d427aa3bf46.png
2019-02-19_222711.png
5.0 我们现在模拟器联系人中添加两位联系人资料:
16102290-52baf5eba4b7fd66.png
2019-02-19_214113.png
16102290-b4282005d28fb8db.png
2019-02-19_214103.png
6.0 在布局文件activity_main.xml添加一个ListView,这里就不用RecyclerView,虽好但也增加了代码量,这里重点也不在这个。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/contacts_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"></ListView>

</android.support.constraint.ConstraintLayout>
7.0 接着修改MainActivity.java中的代码:
package com.example.contactstest;

import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
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 {


    ArrayAdapter<String> adapter;
    List<String> contactsList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //老老实实3步布置好一个简单的ListView列表适配器。
        ListView contactsView = (ListView) findViewById(R.id.contacts_view);
        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactsList);
        contactsView.setAdapter(adapter);

        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {

            //注意,换了权限,READ_CONTACTS危险权限,获取联系人信息
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS}, 1);
        } else {
            readContacts();
        }
    }

    private void readContacts() {
        Cursor cursor = null;
        try {
            //查询联系人数据
           //这里没有传入一个URI参数,没有调用Uri.parse()方法去解析一个内容URI字符串
          //ContactsContract.CommonDataKinds.Phone类已经做好了封装
         //.CONTENT_URI常量就是Uri.parse()解析出来的结果
            cursor =
                    getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI
                            , null, null, null, null);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    //获取联系人姓名
                    String displayName =
                            cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    //获取联系人手机号
                    String number =
                            cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    contactsList.add(displayName + "\n" + number);
                }
                adapter.notifyDataSetChanged();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }

    }
//调用完requestPermissions()方法后,系统会弹出一个权限申请的对话框
    // 无论结果如何,最终都会回调onRequestPermissionsResult()方法
    //授权的结果,会封装在grantResults中。
    // 判断一下,如果同意了授权就打电话,没有就凉凉了……
    @Override
    public void onRequestPermissionsResult(int requestCode,String[] permissions,
                                           int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    readContacts();
                } else {
                    Toast.makeText(this, "抱歉,没有该权限!", Toast.LENGTH_SHORT).show();
                }
        }
    }
}

这里没有传入一个URI参数,没有调用Uri.parse()方法去解析一个内容URI字符串,ContactsContract.CommonDataKinds.Phone类已经做好了封装,CONTENT_URI常量就是Uri.parse()解析出来的结果。

最后千万不要忘记将Cursor对象关闭掉。

9.0 到这里还差最后一步,读取系统联系人的权限千万不能忘记声明。修改AndroidManifest.xml中的代码,增加<uses-permission android:name="android.permission.READ_CONTACTS"/>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.contactstest">

    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
10.0 运行,如下:
16102290-cf5e101d12f12ccf.png
2019-02-19_220635.png

点击“拒绝”:


16102290-67b0cf8e9a0886d3.png
2019-02-19_220640.png

重新运行该程序,点击“允许”:


16102290-207f1a5bf200408d.png
2019-02-19_220711.png
11.0 这里继续补上枯燥的理论知识。

既然已经知道内容URI字符串的格式,那么加载解析成Uri对象可以作为参数传入的代码格式如下:

Uri uri = Uri.parse("content://com.example.app.provider/table1")

只需要调用Uri.parse()方法,就可以将内容URI字符串解析成Uri对象。

12.0 查询table1表中的数据:
 Cursor cursor =getContentResolver().query(
        uri,
        projection,
        selection,
        selectionArgs,
        sortOrder);
  query()方法参数   对应的SQL语句部分     描述
urifrom table_name指定查询某个应用程序下的某一张表
projectionselect column1,column2指定查询的列名
selectionwhere column= value指定where的约束条件
selectionArgs——为where中的占位符提供具体的值
sortOrderorder 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();
       }
13.0 讲完最难的查询操作,增加、修改、删除操作更不在话下。

向table1表中添加一条数据:

           ContentValues values = new ContentValues();
           values.put("column1","text");
           values.put("column2",1);
           getContentResolver().insert(uri,values);

可以看到,将待添加的数据封装到ContentValues 中,然后调用getContentResolver的insert()方法,将Uri和ContentValues 作为参数传入即可。

14.0 向table1表中更新一条数据:

比如把 13.0 中添加的数据中column1的值清空:

           ContentValues values = new ContentValues();
           values.put("column1","");
           getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[] {"text","1"});
15.0 最后,把table1表中这条数据删除掉:
           getContentResolver().delete(uri,"column2 = ? ",new String[] {"1"});

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值