簡介
- 內(nèi)容提供器(Content Provider)主要用于在不同的應(yīng)用程序之間實(shí)現(xiàn)數(shù)據(jù)共享的功能,允許一個程序訪問另一個程序中的數(shù)據(jù),同時保證數(shù)據(jù)的安全性
- 內(nèi)容提供器可以選擇只對一部分?jǐn)?shù)據(jù)進(jìn)行共享
運(yùn)行時權(quán)限
Android權(quán)限機(jī)制詳解
-
Android現(xiàn)在將所有的權(quán)限分成兩類
-
普通權(quán)限
- 不會直接威脅到用戶的安全和隱私的權(quán)限
- 系統(tǒng)會自動幫用戶進(jìn)行授權(quán),不需要手動操作,比如申請網(wǎng)絡(luò)權(quán)限
-
危險權(quán)限
可能觸及到用戶隱私或?qū)υO(shè)備安全性造成影響的權(quán)限(比如獲取設(shè)備聯(lián)系人信息,定位等)
這種權(quán)限,必須用戶手動點(diǎn)擊授權(quán)才行
-
一共有9組24個危險權(quán)限
權(quán)限組名 權(quán)限名 CALENDAR READ_CALENDAR WRITE_CALENDAR CAMERA CAMERA CONTACTS READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS LOCATION ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION MICROPHONE RECORD_AUDIO PHONE READ_PHONE_STATE CALL_PHONE READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS SENSORS BODY_SENSORS SMS SNED_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS STORAGE READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE - 注意:用戶一旦同意授權(quán)了,那么這個授權(quán)對應(yīng)的權(quán)限組中所有的其他權(quán)限也會得到授權(quán)
-
程序運(yùn)行時申請權(quán)限
-
例子:獲取電話權(quán)限
-
首先,先在AndroidManifest.xml中寫入權(quán)限
<uses-permission android:name="android.permission.CALL_PHONE"> -
然后修改ManiActivity中的代碼
public class MainActivity extends AppCompatActivity{ @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); Button makeCall = (Button) findViewById(R.id.make_call); makeCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // checkSelfPermission()方法來判斷用戶是否給指定的權(quán)限授權(quán)了 if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ // 如果沒有授權(quán),調(diào)用requestPermissions()方法向用戶要授權(quán) // 這個方法需要三個參數(shù),第一個是活動的實(shí)例,第二個是一個數(shù)組,要申請的權(quán)限都在這個數(shù)組里,第三個是請求碼,必須是個唯一值 ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE},1); } else { call(); } } }); } private void call(){ try { Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); } catch (SecurityException e){ e.printStackTrace(); } } public void onRequestPermissionResult(int requestCode,String[] permissions,int[] grantResults){ switch (requestCode){ case 1: if (grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ call(); } else{ Toast.makeText(this,"沒有權(quán)限",Toast.LENGTH_SHORT).show(); } break; default: } } }
-
訪問其他程序中的數(shù)據(jù)
ContentResolver的基本用法
對于每一個應(yīng)用程序來說,需要借助ContentResolver類來訪問內(nèi)容提供器共享的數(shù)據(jù)
通過ContentResolver類的getContentResolver()方法獲取該類的實(shí)例
-
ContentResolver類也有對應(yīng)的方法對數(shù)據(jù)進(jìn)行增刪改查,這些方法接收一個Uri參數(shù),這個參數(shù)叫做內(nèi)容URI
-
內(nèi)容URI給內(nèi)容提供器中的數(shù)據(jù)建立了唯一標(biāo)識符,主要由兩部分組成:authority和path
- authority:用于對不同的應(yīng)用程序做區(qū)分,一半是用程序包名的方式命名,比如com.xxx.yy.provider
- path:用于對同一應(yīng)用程序中不同的表進(jìn)行區(qū)分,通常添加在authority后面,比如com.xxx.yy.provider/table1
-
得到內(nèi)容URI字符串之后,還需要解析成URI對象
Uri uri = Uri.parse("content://com.xxx.yy.provider/table1") -
查詢操作
Cursor cursor = getContentResolver().query( uri, projection, selection, selectionArgs, sortOrder ); if (cursor != null){ while (cursor.moveToNext()){ String col1 = cursor.getString(cursor.getColumnIndex("col1")); int col2 = cursor.getInt(cursor.getColumnIndex("col2")); } cursor.close(); }- uri:指定查詢某個應(yīng)用中的某一個表
- project:指定查詢的列名
- selection:指定where的約束條件
- selectionArgs:給where中的占位符提供具體的值
- sortOrder:指定查詢結(jié)果的排序方式
- 查詢結(jié)束之后返回的是一個Cursor對象,然后可以將數(shù)據(jù)從其中讀取出來
-
添加數(shù)據(jù)
Uri uri = Uri.parse("content://com.xxx.yy.provider/table1") ContentValues values = new ContentValues(); values.put("name","Tom"); values.put("age",18); getContentReslover().insert(uri,values); -
修改數(shù)據(jù)
Uri uri = Uri.parse("content://com.xxx.yy.provider/table1") ContentValues values = new ContentValues(); values.put("name","Tom"); getContentReslover().update(uri,values,"name=? and age=?",new Stirng[]{"Tom",15}); -
刪除數(shù)據(jù)
Uri uri = Uri.parse("content://com.xxx.yy.provider/table1") getContentReslover().delete(uri,"age=?",new String[] {45});
-
自定義內(nèi)容提供器
簡單實(shí)現(xiàn)自定義內(nèi)容提供器
可以通過新建一個類去繼承ContentProvider來自定義內(nèi)容提供器
-
ContentProvider類有6個抽象方法,新建的類需要將它們?nèi)恐貙?/p>
import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.net.Uri; public class MyProvider extends ContentProvider { public static final int TABLEONE_DIR = 0; public static final int TABLEONE_ITEM = 1; public static final int TABLETWO_DIR = 2; public static final int TABLETWO_ITEM = 3; private static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.xxx.yy.provider", "tableOne", TABLEONE_DIR); uriMatcher.addURI("com.xxx.yy.provider", "tableOne/#", TABLEONE_ITEM); uriMatcher.addURI("com.xxx.yy.provider", "tableTwo", TABLETWO_DIR); uriMatcher.addURI("com.xxx.yy.provider", "tableTwo/#", TABLETWO_ITEM); } // 在這里完成對數(shù)據(jù)庫的創(chuàng)建和升級的操作,返回true表示內(nèi)容提供器初始化成功,false表示初始化失敗 @Override public boolean onCreate() { return false; } /** * 從內(nèi)容提供器中查詢數(shù)據(jù) * * @param uri:確定查詢哪張表 * @param projection:確定查詢哪些列 * @param selection,selectionArgs:用于約束查詢哪些行 * @param sortOrder:對結(jié)果進(jìn)行排序 * @return cursor:查詢的結(jié)果放在Cursor對象中返回 */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { switch (uriMatcher.match(uri)) { case TABLEONE_DIR: // 查詢表tableOne中所有的數(shù)據(jù) break; case TABLEONE_ITEM: // 查詢表tableOne中的一條數(shù)據(jù) break; case TABLETWO_DIR: // 查詢表tableTWO中所有的數(shù)據(jù) break; case TABLETWO_ITEM: // 查詢表tableTWO中的一條數(shù)據(jù) break; default: break; } return null; } /** * 向內(nèi)容提供器中添加數(shù)據(jù) * * @param uri:確定要添加到哪張表 * @return 返回一個用于表示這條新紀(jì)錄的URI */ @Override public Uri insert(Uri uri, ContentValues values) { return null; } /** * 更新已有的數(shù)據(jù) * * @param uri:確定哪張表 * @param values:新的數(shù)據(jù)保存在values中 * @param selection,selectionArgs:用于約束更新哪些行 * @return 被修改的內(nèi)容作為返回值返回 */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } /** * 更新已有的數(shù)據(jù) * * @param uri:確定哪張表 * @param selection,selectionArgs:用于約束刪除哪些行 * @return 被刪除的內(nèi)容作為返回值返回 */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } /* *根據(jù)傳入的內(nèi)容URI來返回對應(yīng)的MIME類型 */ @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case TABLEONE_DIR: return "vnd.android.cursor.dir/vnd.com.xxx.yy.provider.tableOne"; case TABLEONE_ITEM: return "vnd.android.cursor.item/vnd.com.xxx.yy.provider.tableOne"; case TABLETWO_DIR: return "vnd.android.cursor.dir/vnd.com.xxx.yy.provider.tableTwo"; case TABLETWO_ITEM: return "vnd.android.cursor.item/vnd.com.xxx.yy.provider.tableTwo"; } return null; } }-
MIME類型
-
多用途互聯(lián)網(wǎng)郵件擴(kuò)展類型,設(shè)定某種擴(kuò)展名的文件用一種應(yīng)用程序打開的方式類型
,當(dāng)該擴(kuò)展名文件被訪問的時候,瀏覽器就會自動使用指定的應(yīng)用程序打開它
-
-
getType()方法可以根據(jù)傳入的內(nèi)容URI來返回對應(yīng)的MIME類型
- 內(nèi)容URI對應(yīng)的MIME字符串包含三部分
- 必須以vnd開頭
- 如果內(nèi)容URI以路徑結(jié)尾,那么后面跟上android.curosr.dir/
- 如果內(nèi)容URI以id結(jié)尾,那么后面跟上android.curosr.item/
- 最后接上authority和path
- 內(nèi)容URI對應(yīng)的MIME字符串包含三部分
-
-
URI寫法示例
-
一個標(biāo)準(zhǔn)的URI
content://com.xxx.yy.provider/tableOne
這里表示用戶希望調(diào)用com.xxx.yy這個應(yīng)用中,表tableOne的數(shù)據(jù)
對應(yīng)的MIME字符串:vnd.android.cursor.dir/vnd.com.xxx.yy.provider.tableOne
-
-
指定id
content://com.xxx.yy.provider/tableOne/1- 這里表示用戶希望調(diào)用com.xxx.yy這個應(yīng)用中,表tableOne中,id為1的數(shù)據(jù)
- 對應(yīng)的MIME字符串:vnd.android.cursor.item/vnd.com.xxx.yy.provider.tableOne
以路徑結(jié)尾就表示訪問表中所有的數(shù)據(jù)(比如標(biāo)準(zhǔn)的URI)
以id結(jié)尾表示訪問該表中擁有相應(yīng)id的數(shù)據(jù)