1. 程式人生 > 其它 >四大元件之一 ContentProvider

四大元件之一 ContentProvider

技術標籤:Android 基礎

ContentProvider


前言

本文記錄四大元件之一contentprovider學習,從官方文件 .中學習,從建立資料庫SQLiteOpenHelper,到利用提供者分享資料,監聽內容變化,只記錄簡單的方法的使用和一些小事例,

ContentProvider的概述

內容提供程式有助於應用管理其自身和其他應用所儲存資料的訪問,並提供與其他應用共享資料的方法。它們會封裝資料,並提供用於定義資料安全性的機制。內容提供程式是一種標準介面,可將一個程序中的資料與另一個程序中執行的程式碼進行連。最重要的是,通過配置內容提供程式,您可以使其他應用安全地訪問和修改您的應用資料。

簡而言之:則是提供一個標準介面,給外部應用操作自己應用的資料庫。

資料庫的建立

  • 繼承SQLiteOpenHelper類 建立資料庫
    • 構造方法 初始化資料庫 (上下文,資料庫名,遊標卡尺,版本號)cursor用於查詢資料的箭頭預設指向第一個資料。版本號
    • oncreate方法 建立資料庫用的 一般通過sql語句 一般用到的型別是integer和varchar
    • onupdate方法 用於版本升級,當資料庫需擴充套件時,通過sql語句來擴充套件,最新版本號必須大於等於應用版本號 不然報錯
  • 建立Dao類操作資料庫
    • 操作資料庫需持有SQLiteOpenHelper幫助類,通過幫助類來進行增刪改查方法。
    • 增:可以通過sql語句或者api來進行,api ,使用幫助類的insert方法 (表名,null,contentvalues) null表示當插入資料為空所填數值,資料通過contentvalues的鍵值對方式put該方法成功返回1,錯誤返回-1
    • 刪: 可以通過sql語句或者api來進行,api ,使用幫助類的delete方法 (表名,null,null) 第一個null表示: whereClause條件,第二個null表示whereArgs條件下的值,該方法成功返回刪除資料個數,錯誤返回-1
    • 改:可以通過sql語句或者api來進行,api ,使用幫助類的update方法 (表名,contentvalues,null,null 第一個null表示: whereClause條件,第二個null表示whereArgs條件下的值
    • 查: 可以通過sql語句或者api來進行,api ,使用幫助類的query方法
      (表名,列表數columns,查詢那列selection,查詢那列的條件值selectionArgs,groupBy,having,orderBy)
  • 建立Bean類 封裝資料

ContentProvider 的使用

  • 繼承ContentProvider
    • 這裡有暴露給外部應用的操作資料庫的方法 增刪改查方法 getType方法 onCreate方法
    • onCreate方法 建立SQLiteOpenHelper幫助類操作資料庫
    • 增刪改查方法應用操作幫助類的方法,和Uri ,它是用來匹配外部應用是否使用改資料庫的校驗。所以需要new UriMatcher(UriMatcher.NO_MATCH)物件 和靜態程式碼塊初始化Uri地址(靜態的在記憶體中執行) UriMatcher的addURI方法(校驗號,path,校驗返回碼)校驗號返回碼。 在增刪改查方法,通過外部app傳入的url和static程式碼中校驗號/path進行比對放回。
  • 清單檔案許可權在清單檔案中註冊provider android:name=繼承類 ,android:authorities=靜態程式碼塊註冊的校驗號,android:exported=true
  • 在外部應用中,通過getContentResolver獲取ContentResolver物件 來操作資料庫

內容觀察者

  • 在外部應用中利用ContentResolver物件呼叫增刪改查方法。來操作應用中的資料庫。該物件的增刪改查方法的引數對應著所寫 ContentProvider類中的引數。

  • 在外部應用中利用ContentResolver物件註冊內容觀察者來監聽該資料庫中資料變化。registerContentObserver(Uri,true,new ContentObserver(new Handler)) true:表示uri 不管後面是否有path都能返回, 內容觀察者是當內容發生改變,你要監聽的資訊。

日曆事件的運用

日曆提供者
一鍵插入事件,通過ContentResolver物件 insert方法
以下是插入新事件的規則:

  • 您必須加入 CALENDAR_ID 和 DTSTART。
  • 您必須加入 EVENT_TIMEZONE。如需獲取系統中已安裝時區 ID 的列表,請使用 getAvailableIDs()。請注意,如果您按使用 Intent 插入事件中所述通過 INSERT Intent 插入事件,則此規則不適用 — 在該情形下,系統會提供預設時區。
  • 對於非重複事件,您必須加入 DTEND。
  • 對於重複事件,您必須加入 DURATION,以及 RRULE 或 RDATE。請注意,如果您按使用 Intent 插入事件中所述通過 INSERT Intent 插入事件,則此規則不適用 — 在該情形下,您可以將 RRULE 與 DTSTART 和 DTEND 結合使用,日曆應用會自動將其轉換為持續時間。
  //1:事件表 2.應用weibo相關資訊表 3:聯絡人生日表
        long calID = 1;
        long startMillis = 0;
        long endMillis = 0;
        Calendar beginTime = Calendar.getInstance();
        beginTime.set(2021, 10, 11, 0, 0);
        startMillis = beginTime.getTimeInMillis();
        Calendar endTime = Calendar.getInstance();
        endTime.set(2021, 10, 11, 23, 59);
        endMillis = endTime.getTimeInMillis();

        String timeZone= TimeZone.getDefault().getID();
        Log.d(TAG,timeZone);

        ContentResolver cr = getContentResolver();
        ContentValues eventValues = new ContentValues();
        eventValues.put(CalendarContract.Events.DTSTART, startMillis);
        eventValues.put(CalendarContract.Events.DTEND, endMillis);
        eventValues.put(CalendarContract.Events.TITLE, "雙十一購物狂歡節開搶");
        eventValues.put(CalendarContract.Events.DESCRIPTION, "盡情買買買!!");
        eventValues.put(CalendarContract.Events.CALENDAR_ID, calID);
        eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, timeZone);
        Uri resultUri = cr.insert(CalendarContract.Events.CONTENT_URI, eventValues);
        Log.d(TAG,"返回結果"+resultUri);

        String eventID = resultUri.getLastPathSegment();
        Log.d(TAG,eventID);
        ContentValues reminderValues = new ContentValues();
        reminderValues.put(CalendarContract.Reminders.MINUTES, 15);
        reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventID);
        reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
        Uri uri1 = cr.insert(CalendarContract.Reminders.CONTENT_URI, reminderValues);

聯絡人提供者

ContentResolver cr = getContentResolver();
        Uri rawUri = Uri.parse("content://"+ContactsContract.AUTHORITY+"/raw_contacts");
        Cursor rawCursor = cr.query(rawUri, new String[]{"contact_id","display_name"}, null, null, null);
        String[] columnNames = rawCursor.getColumnNames();

        List<UserInfo> userInfos=new ArrayList<>();
        while (rawCursor.moveToNext()) {
            UserInfo userInfo=new UserInfo();
            userInfo.setId(rawCursor.getString(rawCursor.getColumnIndex("contact_id")));
            userInfo.setDisplayName(rawCursor.getString(rawCursor.getColumnIndex("display_name")));
            userInfos.add(userInfo);
            for (String columnName : columnNames) {
                Log.d(TAG,columnName+" ======= "+rawCursor.getString(rawCursor.getColumnIndex(columnName)));
            }
        }
        rawCursor.close();
        Uri phoneUri = Uri.parse("content://"+ContactsContract.AUTHORITY+"/data/phones");
        for (UserInfo userInfo : userInfos) {
            Cursor phoneCursor = cr.query(phoneUri, new String[]{"data1"}, "raw_contact_id=?", new String[]{userInfo.getId()}, null);
            if (phoneCursor.moveToNext()) {
                userInfo.setPhoneNumber(phoneCursor.getString(0).replace("-",""));
            }
            Log.d(TAG,"userInfo ===>"+userInfo);
            phoneCursor.close();
        }
        /*for (UserInfo userInfo : userInfos) {
            Cursor phoneCursor = cr.query(phoneUri, null, "raw_contact_id=?", new String[]{userInfo.getId()}, null);
            String[] columnNames1 = phoneCursor.getColumnNames();
            while (phoneCursor.moveToNext()) {

                for (String columnName : columnNames1) {
                    Log.d(TAG, columnName + " ======= " + phoneCursor.getString(phoneCursor.getColumnIndex(columnName)));
                }
            }
            phoneCursor.close();
        }*/

這裡只能讀到手機的聯絡人手機號,sd卡上無法讀取。但能看到聯絡人的名字,可能得通過另一個數據庫去查詢。

訊息提供者

 ContentResolver contentResolver = getContentResolver();
        Uri uri=Uri.parse("content://sms");
        Cursor cursor = contentResolver.query(uri, null, null, null, null);
        String[] columnNames = cursor.getColumnNames();
        while (cursor.moveToNext()) {
            for (String columnName : columnNames) {
                Log.d(TAG,columnName+" ==== "+cursor.getString(cursor.getColumnIndex(columnName)));
            }
        }
        cursor.close();

通過registerContentObserver 內容觀察者來獲取訊息的實時驗證嗎

  1. 通過監聽sms的資料庫變化,獲取資料變化的Uri
  2. 通過Uri查詢資料庫的簡訊
  3. 對簡訊進行正則化表示式過濾獲取 驗證碼

獲取媒體庫提供者形成9宮圖返回

  • LoadManager獲取資料庫資訊
    • 如果圖片很多時,由於訪問資料庫耗時操作很多,所以需要在子執行緒中執行,所以運用LoadManager
    • LoadManager.getInstance()獲取LoadManager物件
    • 呼叫LoadManager的init方法(load_id,args,Callback) 通過Callback的onCreatLoader方法根據load_id,建立返回的Cursor物件,return new CursorLoad(context,uri,projection,selection,selectionArgs,sortOrder);
    • Callback的onLoadFinished方法中得到cursor物件,通過query方法查詢需要的資訊"_data",“display_name”,“date_added” 並將資料封裝到ArrayList當中。
  • 將資料庫資訊載入到RecyclerView的介面卡中
    • 建立RecyclerView(1.找到控制元件2.設定LayoutManager3.設定Adapter)
    • 將封裝好的資料ArrayList物件資料設定Adapter(1.私有化資料2.清空3.重新新增防止資料錯亂)
  • 載入佈局到RecyclerView當中
    • onCreateViewHolder的建立複用itemView的Holder物件(1.通過獲取WindowManager物件 2.itemView設定LayoutParams 3等分)
    • onBindViewHolder繫結資料(資料改變的呼叫)初始化控制元件,控制元件點選事件(imageview,checkbox,view(背景色))
  • 控制元件點選事件設計
    • imageview的點選
      • 點選一下選擇,再點選取消。
      • 建立被選擇的ArrayList,根據是否包含被選擇,如果選擇,點選remove的條目,checkbox的setChecked,setButtonDrawable和view變setVisibility(View.GONE)。如果沒選擇,則相反。
  • 將選擇的資料通過介面返回到Activity中
    • 建立Config,設定回撥介面set方法和get方法,回撥介面返回選擇的圖片item物件,設定最大圖片數的get和set方法。
    • 防止洩漏設定成單例模式,由於執行緒無關,設定成餓漢式
    • 在選擇圖片介面finish的 set回撥介面 是否判斷介面為空,返回介面
    • 在返回介面get回撥介面