第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Android 入門教程

菜單類控件
菜單:Menu
并發(fā)編程
多線程
首頁 慕課教程 Android 入門教程 Android 入門教程 內(nèi)容提供者 - Content Provider

內(nèi)容提供者 - Content Provider

本節(jié)學(xué)習(xí)最后一個 Android 組件——內(nèi)容提供者。顧名思義,它可以用來給其他的 App 提供各種內(nèi)容,比如 Android 自帶的短信、聯(lián)系人、日歷等等都是一個普通的 App,當(dāng)你需要這些內(nèi)容的時候,就可以向它們的 Content Provider 發(fā)起請求,然后拿到相應(yīng)的數(shù)據(jù)。

1. 內(nèi)容提供者的定義

照舊,首先看看官方解釋:

Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications. For example, the contacts data is used by multiple applications and must be stored in a content provider. If you don’t need to share data amongst multiple applications you can use a database directly via android.database.sqlite.SQLiteDatabase.
When a request is made via a ContentResolver the system inspects the authority of the given URI and passes the request to the content provider registered with the authority. The content provider can interpret the rest of the URI however it wants. The UriMatcher class is helpful for parsing URIs.

文檔解釋略長,這里用自己的話簡要描述一發(fā):

Content Provider 是 Android 四大組件之一,通過它可以向其他 App 提供數(shù)據(jù)。當(dāng)收到其他 App 的數(shù)據(jù)請求時,會有一個 Content Resolver 接口統(tǒng)一對請求進行處理。數(shù)據(jù)請求通過 URI 的形式發(fā)起,每一次請求都需要帶上 URI,Content Resolver 非常靈活并且可控性很強,在這里我們可以對來訪者做鑒權(quán),然后根據(jù)權(quán)限的不同給予不同敏感級別的數(shù)據(jù),甚至可以對部分 App 拒絕提供數(shù)據(jù)。Content Provider 對數(shù)據(jù)的管理方式并不關(guān)心,可以采用 DataBase、文件、遠(yuǎn)程服務(wù)端等等 Android 支持的任何一種形式,整個工作流程如下:

ContentProvider

2. 為什么需要內(nèi)容提供者

首先我們聊聊 Content Provider 存在的意義,在 Android 中每個 App 運行于一個獨立的進程,而不同進程之間一般是無法直接通信的,所以一個 App 里的數(shù)據(jù)不能直接共享給其他 App 使用,這就會讓很多功能難以實現(xiàn)。
在 Android 系統(tǒng)中我們可以很簡單的創(chuàng)建 DataBase 來管理我們的數(shù)據(jù),但是出于安全性的考慮,DataBase 只能在 App 內(nèi)部使用,App 之間是無法共享內(nèi)存的。因此,為了能夠方便的將自己的數(shù)據(jù)共享出去,Android 系統(tǒng)引入了 Content Provider 組件,讓我們可以和其他的 App 很方便的進行數(shù)據(jù)交換,甚至可以用來做 IPC(進程間通信),這就是內(nèi)容提供者存在的意義。

不適合的使用場景:
當(dāng)你使用了內(nèi)容提供者,就表示你的數(shù)據(jù)是對外暴露的,所以這是一個相對敏感的操作,很多 App 的漏洞都是由于 Content Provider 使用不當(dāng)導(dǎo)致的,所以這里需要多加注意。
Content Provider 不僅僅可以很方便的對其他 App 提供數(shù)據(jù),當(dāng)然也可以給 App 內(nèi)部其他模塊、或者 App 的其他進程提供數(shù)據(jù),在多人、多業(yè)務(wù)合作的場景下使用 Content Provider 確實很便利。但是要注意的是,如果共享的數(shù)據(jù)僅僅是一個 App 私有的數(shù)據(jù),最好不要使用 Content Provider。

3. Content Provider 相關(guān)概念

在編寫 Content Provider 之前,我們先來熟悉幾個概念:

3.1 Content URI

Content URI 可以用來讓 provider 唯一標(biāo)識一個數(shù)據(jù),它包括四個部分:

  • Scheme: Content Provider 的 Scheme 是固定的字符串——“content”
  • Authority: provider 的唯一標(biāo)識,我們通過“Authority”字段來從眾多的 Content Provider 中找到我們想要的那個。
  • Path: path 字段幫助我們描述出我們想要的最具體的數(shù)據(jù)。比如我們想要查詢通話記錄,可以通過不同的 path 來查詢具體的“未接來電”、“播出來電”、“已接來電”等等。
  • ID: 數(shù)字類型的可選字段,在一些特殊場景下可以使用 ID 來區(qū)分不同的類別。

3.2 身份鑒權(quán)

在 Content Resolver 中使用對請求者的身份進行鑒權(quán),通過 URI 中的 Authority 字段我們可以區(qū)分出不同的請求者。然后根據(jù)請求者的 path 字段和 ID 字段(如果有 ID)我們能夠精準(zhǔn)的知道它想要的數(shù)據(jù),最后可以根據(jù)它的權(quán)限等級來給它提供相應(yīng)的數(shù)據(jù)。

Authority

4. Content Provider 的常用操作

常用操作基本上就是下面四種,和數(shù)據(jù)庫非常類似:

  1. 查詢(Querying):
    查詢某個 Content Provider 支持的所有數(shù)據(jù)對象
  2. 刪除(Delete):
    從 Content Provider 的數(shù)據(jù)庫中刪除具體的數(shù)據(jù)對象
  3. 更新(Update):
    更新數(shù)據(jù)對象
  4. 插入(Insert):
    插入一個新的數(shù)據(jù)對象
  5. onCreate():
    在 provider 被創(chuàng)建的時候回調(diào)

Operation

5. Content Provider 使用示例

和 Broadcast 類似,Android 系統(tǒng)也為我們預(yù)置了很多必備的 Content Provider,我們來學(xué)習(xí)一下如何使用。

5.1 讀取短信收件箱

Android 系統(tǒng)中短信也是一個 App,為了方便其他 App 讀取短信(比如接收驗證碼),短信提供了一個 Content Provider 接口供我們使用,當(dāng)然讀取短信屬于敏感操作,必須添加以下權(quán)限:

    <uses-permission android:name="android.permission.READ_SMS"/>

在 Android 6.0 以前只需要靜態(tài)注冊權(quán)限即可,但是這個年代應(yīng)該沒有多少 Android 6.0 以下的機型了。在 6.0 之后我們還需要在代碼中動態(tài)申請權(quán)限,然后通過content://sms/來查詢短信消息,代碼如下:


package com.emercy.myapplication;

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity implements View.OnClickListener {

    private static final String TAG = "ContentProvider";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.get_sms).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            int hasReadSmsPermission = checkSelfPermission(Manifest.permission.READ_SMS);
            if (hasReadSmsPermission != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.READ_SMS}, 100);
                return;
            }
        }

        Uri uri = Uri.parse("content://sms/");
        ContentResolver resolver = getContentResolver();
        //獲取的是哪些列的信息
        Cursor cursor = resolver.query(uri, new String[]{"address", "date", "type", "body"}, null, null, null);
        while (cursor.moveToNext()) {
            String address = cursor.getString(0);
            String date = cursor.getString(1);
            String type = cursor.getString(2);
            String body = cursor.getString(3);
            Log.d(TAG, "地址:" + address);
            Log.d(TAG, "時間:" + date);
            Log.d(TAG, "類型:" + type);
            Log.d(TAG, "內(nèi)容:" + body);
        }
        cursor.close();
    }
}

contentView 的布局代碼就不貼了,只需要一個 Button 即可。在 onClick 方法中我們首先申請權(quán)限,此時手機會彈出一個權(quán)限申請的彈窗,入剩下:
sms_permision
點擊同意之后就可以觀察 Logcat 了,過濾 Tag 為 ContentProvider,結(jié)果如下:

get_sms

這樣就能夠順利讀取出短信相關(guān)的信息了。

5.2 讀取聯(lián)系人

其他的代碼和讀取短信一樣,修改的部分就是onClick()中的部分,主要是權(quán)限申請和數(shù)據(jù)讀取,修改 onClick() 中的代碼如下:

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            int hasReadSmsPermission = checkSelfPermission(Manifest.permission.READ_CONTACTS);
            if (hasReadSmsPermission != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 100);
                return;
            }
}

ContentResolver resolver = getContentResolver();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
Cursor cursor = resolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
            String cName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            String cNum = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            Log.d(TAG, "姓名:" + cName);
            Log.d(TAG, "號碼:" + cNum);
        }
cursor.close();

然后在 AndroidManifest.xml 中加入讀取聯(lián)系人的權(quán)限:

<uses-permission android:name="android.permission.READ_CONTACTS"/>

第一次點擊的時候同樣會彈出以下權(quán)限申請彈出,授予之后即可拿到具體的聯(lián)系人信息。

contact_permission

掌握了這兩種 Content Provider 的使用,其余的像新增聯(lián)系人、查詢具體聯(lián)系人等等其實都是換湯不換藥,核心思路就是兩步:1、申請權(quán)限(Android 6.0 以上需要動態(tài)申請);2、通過 URI 讀取數(shù)據(jù)。

6. 小結(jié)

本節(jié)學(xué)習(xí)最后一個 Android 組件,它的功能是為其他 App 提供相關(guān)的數(shù)據(jù),讓數(shù)據(jù)可以在不同 App、不同進程之間相互共享,但是要注意的是它的適用場景,一定只是在向其他 App 輸出數(shù)據(jù)的時候用,為了避免數(shù)據(jù)泄露出現(xiàn)安全風(fēng)險,其他場景要慎用。使用 Content Provider 首先關(guān)注一下改數(shù)據(jù)是否需要申請權(quán)限,然后查詢到該數(shù)據(jù)的 URI,通過拼接 URI 就可以完成數(shù)據(jù)的獲取了。