【Android】20.0 權(quán)限處理(二)——訪問其他程序數(shù)據(jù):讀取聯(lián)系人信息

1.0 在我的上一篇,相當(dāng)于運行時權(quán)限的初體驗抢肛,這一篇主要是怎么訪問其他程序的數(shù)據(jù),比如接下來的這個例子碳柱,將手機聯(lián)系人應(yīng)用中的聯(lián)系人數(shù)據(jù)捡絮,讀取出來,在APP中展示莲镣。
2.0 一個應(yīng)用程序通過內(nèi)容提供器可以對其數(shù)據(jù)提供外部訪問接口福稳,其他任何應(yīng)用程序都可以對這部分?jǐn)?shù)據(jù)進(jìn)行訪問。

Android系統(tǒng)自帶的電話簿瑞侮、短信的圆、媒體庫等程序都提供了類似的訪問接口,這使得第三方應(yīng)用程序可以充分地利用這部分?jǐn)?shù)據(jù)來實現(xiàn)更好的功能半火。

3.0對于每一個應(yīng)用程序來說越妈,如果想訪問內(nèi)容提供器中共享的數(shù)據(jù),就一定要借助ContentResolver類钮糖,可以通過Context中的getContentResolve方法獲得該類的實例梅掠。

ContentResolver中提供了一系列的方法用于增刪查改操作。不錯店归,和SQLiteDatabase很相似阎抒。

不同于SQLiteDatabase,ContentResolver使用的是內(nèi)容URI參數(shù)娱节。
標(biāo)準(zhǔn)格式為:
content://com.example.app.provider/table1
content://com.example.app.provider/table2

內(nèi)容URI主要由2部分組成:authority和path挠蛉。

  • authority:用于對不同應(yīng)用程序做區(qū)分的祭示,一般為了避免沖突肄满,都會采用程序包名的方式來命名谴古。
    比如某個程序包名為com.example.app,該程序的authority就可以命名為com.example.app.provider

  • path:用于對同一應(yīng)用程序中不同的表做以區(qū)分稠歉,通常添加在authority后面掰担。

4.0 閑話放最后說,先上車直接干代碼怒炸,新建項目ContactsTest带饱,目錄如下:
2019-02-19_222711.png
5.0 我們現(xiàn)在模擬器聯(lián)系人中添加兩位聯(lián)系人資料:
2019-02-19_214113.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) {

            //注意执庐,換了權(quán)限,READ_CONTACTS危險權(quán)限导梆,獲取聯(lián)系人信息
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS}, 1);
        } else {
            readContacts();
        }
    }

    private void readContacts() {
        Cursor cursor = null;
        try {
            //查詢聯(lián)系人數(shù)據(jù)
           //這里沒有傳入一個URI參數(shù)轨淌,沒有調(diào)用Uri.parse()方法去解析一個內(nèi)容URI字符串
          //ContactsContract.CommonDataKinds.Phone類已經(jīng)做好了封裝
         //.CONTENT_URI常量就是Uri.parse()解析出來的結(jié)果
            cursor =
                    getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI
                            , null, null, null, null);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    //獲取聯(lián)系人姓名
                    String displayName =
                            cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    //獲取聯(lián)系人手機號
                    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();
            }
        }

    }
//調(diào)用完requestPermissions()方法后,系統(tǒng)會彈出一個權(quán)限申請的對話框
    // 無論結(jié)果如何看尼,最終都會回調(diào)onRequestPermissionsResult()方法
    //授權(quán)的結(jié)果递鹉,會封裝在grantResults中。
    // 判斷一下藏斩,如果同意了授權(quán)就打電話躏结,沒有就涼涼了……
    @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, "抱歉,沒有該權(quán)限狰域!", Toast.LENGTH_SHORT).show();
                }
        }
    }
}

這里沒有傳入一個URI參數(shù)窜觉,沒有調(diào)用Uri.parse()方法去解析一個內(nèi)容URI字符串,ContactsContract.CommonDataKinds.Phone類已經(jīng)做好了封裝北专,CONTENT_URI常量就是Uri.parse()解析出來的結(jié)果禀挫。

最后千萬不要忘記將Cursor對象關(guān)閉掉。

9.0 到這里還差最后一步拓颓,讀取系統(tǒng)聯(lián)系人的權(quán)限千萬不能忘記聲明语婴。修改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 運行驶睦,如下:
2019-02-19_220635.png

點擊“拒絕”:


2019-02-19_220640.png

重新運行該程序砰左,點擊“允許”:


2019-02-19_220711.png
11.0 這里繼續(xù)補上枯燥的理論知識。

既然已經(jīng)知道內(nèi)容URI字符串的格式场航,那么加載解析成Uri對象可以作為參數(shù)傳入的代碼格式如下:

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

只需要調(diào)用Uri.parse()方法缠导,就可以將內(nèi)容URI字符串解析成Uri對象。

12.0 查詢table1表中的數(shù)據(jù):
 Cursor cursor =getContentResolver().query(
        uri,
        projection,
        selection,
        selectionArgs,
        sortOrder);
??query()方法參數(shù) ???對應(yīng)的SQL語句部分 ?????描述
uri from table_name 指定查詢某個應(yīng)用程序下的某一張表
projection select column1,column2 指定查詢的列名
selection where column= value 指定where的約束條件
selectionArgs —— 為where中的占位符提供具體的值
sortOrder order by column1,column2 指定查詢結(jié)果的排序方式

查詢完后返回的也是一個Cursor對象溉痢,逐個讀出即可僻造,通過移動游標(biāo)位置來遍歷Cursor所有行憋他,然后再去除每一行相應(yīng)列的數(shù)據(jù):

 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表中添加一條數(shù)據(jù):

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

可以看到立膛,將待添加的數(shù)據(jù)封裝到ContentValues 中揪罕,然后調(diào)用getContentResolver的insert()方法,將Uri和ContentValues 作為參數(shù)傳入即可宝泵。

14.0 向table1表中更新一條數(shù)據(jù):

比如把 13.0 中添加的數(shù)據(jù)中column1的值清空:

           ContentValues values = new ContentValues();
           values.put("column1","");
           getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[] {"text","1"});
15.0 最后好啰,把table1表中這條數(shù)據(jù)刪除掉:
           getContentResolver().delete(uri,"column2 = ? ",new String[] {"1"});

END

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市儿奶,隨后出現(xiàn)的幾起案子坎怪,更是在濱河造成了極大的恐慌,老刑警劉巖廓握,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搅窿,死亡現(xiàn)場離奇詭異,居然都是意外死亡隙券,警方通過查閱死者的電腦和手機男应,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娱仔,“玉大人沐飘,你說我怎么就攤上這事∩龋” “怎么了耐朴?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盹憎。 經(jīng)常有香客問我筛峭,道長,這世上最難降的妖魔是什么陪每? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任影晓,我火速辦了婚禮,結(jié)果婚禮上檩禾,老公的妹妹穿的比我還像新娘挂签。我一直安慰自己,他們只是感情好盼产,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布饵婆。 她就那樣靜靜地躺著,像睡著了一般戏售。 火紅的嫁衣襯著肌膚如雪侨核。 梳的紋絲不亂的頭發(fā)上草穆,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機與錄音芹关,去河邊找鬼续挟。 笑死紧卒,一個胖子當(dāng)著我的面吹牛侥衬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播跑芳,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼轴总,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了博个?” 一聲冷哼從身側(cè)響起怀樟,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盆佣,沒想到半個月后往堡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡共耍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年虑灰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痹兜。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡穆咐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出字旭,到底是詐尸還是另有隱情对湃,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布遗淳,位于F島的核電站拍柒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屈暗。R本人自食惡果不足惜斤儿,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恐锦。 院中可真熱鬧往果,春花似錦、人聲如沸一铅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潘飘。三九已至肮之,卻和暖如春掉缺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背戈擒。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工眶明, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筐高。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓搜囱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親柑土。 傳聞我的和親對象是個殘疾皇子蜀肘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容