標籤:update display 聯絡 stp 針對 tac http 讀取 成功
什麼是內容提供器?
跨程式共用資料之內容提供器,這是個什麼功能?看到這個名稱的時候最能給我們提供資訊的應該是“跨程式”這個詞了,是的重點就是這個詞,這個內容提供器的作用主要是用於在不同的引用程式之間實現資料共用的功能,它提供了一完整的機制,允許一個程式訪問另一個程式中的資料,同時還能保證被訪問的資料的安全性,在目前使用內容提供器是Android實現跨程式共用資料的標準方式。不同於檔案儲存體和SharePreferences儲存中的兩種全域可讀性操作模式,內容提供器可以選擇只對那一部分資料進行共用,從而保證我們程式中的隱私資料不糊有泄漏的風險。
不過在理解這個內容提供器之前,我們需要理解Android的運行時許可權,這個就不需要我們解釋什麼是運行時許可權了,因為我們在之前其實已經使用過,比如“相機許可權”,“照片許可權”,“位置許可權”等等!
運行時許可權
Android 將所有的許可權大致的分為兩類,一類是普通許可權,另一類是危險許可權,我們在下面將危險的許可權整理了出來,供以後我們參考使用:
舉個小栗子
下面是針對打電話我們寫的一個小Demo,其實邏輯很簡單,說的直接點就是一句話“有許可權直接打電話,沒有許可權就請求完了再打”。下面是點擊事件我們做的操作
// 利用checkSelfPermission這個函數檢查有沒有運行時許可權 // 有許可權就直接調用下面的call()方法,沒有就請求許可權 // checkSelfPermission(MainActivity.this, android.Manifest.permission.CALL_PHONE) 是否等於PackageManager.PERMISSION_GRANTED // PERMISSION_GRANTED 同意許可權 if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ // ActivityCompat的requestPermissions請求許可權 // 第二個參數是一個String數組,我們需要把申請的許可權名稱放到數組中即可 // 第三個參數是請求碼,這個請求碼我們在下面許可權回調的時候可以用來做判斷,判斷是那個許可權再做相應的操作 ActivityCompat.requestPermissions(MainActivity.this,new String[]{ android.Manifest.permission.CALL_PHONE},1); }else { call(); }
接著就是我們打電話的call()方法的操作,以及最後許可權請求回來之後的回調方法:
// 防止有異常發生,寫在這裡 public void call(){ try { Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); }catch (SecurityException e){ e.printStackTrace(); } } //所有的許可權回調都是在這裡,我們根據requestCode來判斷是哪個許可權 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 1: if (grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ call(); }else { Toast.makeText(this,"打電話需要許可權才能使用",Toast.LENGTH_LONG).show(); } } }
訪問其他程式中的資料需要-ContentResolver
對於每一個應用程式來說,如果你想要訪問內容提供器當中共用的資料,就一定要藉助 ContentResolver 類,可以通過Context類當中的getContentResolver()方法來擷取該類的執行個體, ContentResolver 類當中也提供了一系列的方法用於對資料進行CRUD的操作, insert() 添加 update() 更新 delete() 刪除 query() 查詢
不同於SQLiteDatabase,ContentResolver的CRUD的操作是不接收表名參數的,而是使用一個Uri參數表示。這個參數被稱為內容URI,內容URI給內容提供器中的資料表建立了唯一的標識符,它主要是由兩部分組成,一部分是 authority,它是用於對不同的應用程式做區分,一般為了避免衝突,都會採取程式包的方式來進行命名, 另一部分是path,path則是相對於同一應用程式中的表走區分的,通常都是添加在authority的後面。當然只有這兩部分還是不夠的,我們需要在前面加上協議聲明,因此標準的形式我們舉個例子:
content://com.example.app.provider/table1 當中content://是我們頭部的協議 com.example.app.provider是authority /table1就是path
上面我們得到一個URI字串之後,我們還需要將它解析成Uri對象才能使用,解析的方法也很簡單如下:
Uri uri = Uri.parse("content://com.example.app.provider/table1")
有了這個Uri這個對象之後,我們就可以利用它來查詢資料了,代碼如下:
Cursor cursor = getContentResolver().query(
uri, 指定查詢某一個應用下面的某張表
projection, 指定查詢的列名
selection, 指定where的約束條件
selectionArgs, 為where中的預留位置提供具體的值
sortOrder); 指定查詢結果的排序方式
查詢完成之後返回的仍然是一個Cursor對象,這時候我們就可以將資料從Cursor對象中逐個讀取出來了,
讀取的思路仍然是通過移動遊標的位置來遍曆Cursor的所有行沒然後再取出每一個行中國的資料沒代碼如下:
if(cursor != null){
while(cursor.moveNext()){
String column1 = cursor.getString(cursor.getColumnIndex("column1"));
Int column1 = cursor.getInt(cursor.getColumnIndex("column1"));
}
}
掌握了比較複雜的查詢之後,剩下的增加,刪除,修改就比較簡單了,我們也就不在說了!
我們讀取一下連絡人
我們這裡寫一個小demo,來讀取一下連絡人的資訊,然後把它展示在一個ListView當中,具體的代碼如下:
public class ContactsActivity extends AppCompatActivity { //適配器和一個數組,用來儲存連絡人資訊 ArrayAdapter<String> adapter; List<String> list = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contacts); ListView contactsList = (ListView) findViewById(R.id.contactsListView); adapter = new ArrayAdapter<String>(ContactsActivity.this, android.R.layout.simple_list_item_1, list); contactsList.setAdapter(adapter); // 先檢查有沒有擷取通訊錄的許可權,要是沒有就先請求許可權 if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.READ_CONTACTS},2); }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 displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); // 連絡人的手機號 String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); list.add(displayName+"\n"+number); } // 給適配器發訊息說資料改變了,這時候會重新重新整理一次資料 adapter.notifyDataSetChanged(); } }catch (Exception e){ e.printStackTrace(); }finally { if (cursor != null){ cursor.close(); } } } // 擷取許可權結果 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 2: if (grantResults.length>0&& grantResults[0] == PackageManager.PERMISSION_GRANTED){ readContacts(); }else { Toast.makeText(this,"訪問通訊錄需要許可權",Toast.LENGTH_SHORT).show(); } } }}
建立自己的內容提供器
前面也說過,要是想實現跨程式之間的共用資料的功能,官方推薦的就是使用內容提供器,我們可以建立一個類去繼承ContentProvider的方式來建立一個自己的內容提供器。ContentProvider裡面的6個抽象方法我們全部重寫
onCreate()
初始化內容提供器的時候調用,通常會在這裡完成資料庫的建立和升級操作,返回true表示成功,返回false表示失敗,注意的是只有當ContentResolver嘗試訪問我們的資料庫的時候內容提供器才會被初始化
query()
從內容提供器中查詢資料,使用uri參數來確定查詢哪張表,具體的參數我們就不在說了,前面我們已經說過,查詢的具體的結果就在cursor對象中存放返回
insert()
添加資料我們也就不再說了,成功之後會返回一個用於表示這條記錄的URI
update()
注意的就一點,受影響的函數將作為傳回值返回
delete()
這個和更新一樣也是將受影響的行數作為傳回值返回
getType()
根據傳入的內容URI來返回相應的MIME類型
方法具體的內容我們就不在多說了,可以自己點進類裡面去看看。有一點需要注意的就是URI,有一點需要我們注意:
* 表示匹配任意長度的任一字元
# 表示匹配任意長度的數字
所以,我們把一個能夠匹配任意表的內容URI可以寫成:content://com.example.app.provider/*
我們把一個能夠匹配表中任意一行資料的內容URI可以寫成:content://com.example.app.provider/table1/#
最後還有一個問題,就是內容URI的匹配問題,有個類UriMatcher類可以瞭解一下,我們就不在多說了,想想你匹配好了URI,當外面使用者進行CRUD操作的時候具體的返回內容就是我們自己自訂的了!以上就是我們要說的關於內容控制器的內容!
Android學習--跨程式共用資料之內容提供其探究