目錄
- 7.1 簡介
- 7.2 運行時權限
- 7.2.1 權限機制詳解
- 7.2.2 在程式運行時申請權限
- 7.3 訪問其他程式中的資料
- 內容URI
- 創建自己的內容提供器
- 使用現有的內容提供器來讀取和操作相應程式中的資料
7.1 簡介
內容提供器主要用于在不同應用程式之間實作資料共享的功能,他可以選擇只對那一部分資料進行共享,從而保證我們程式中的隱私資料不會有泄漏的風險,
例子:微信讀取手機聯系人資訊
7.2 運行時權限
7.2.1 權限機制詳解
Android開發團隊在6.0系統中加入了運行時權限功能,即用戶不需要在安裝程式時一次性授權所有權限,可以在軟體運行程序中再對某一權限進行授權,
Android吧所有的權限大致分為兩類,一類是普通權限,一類是危險權限,
普通權限指不會威脅到用戶的安全和隱私的權限,對于這部分權限申請,系統自動幫我們進行授權,
危險權限表示那些可能觸及用戶隱私或者對設備安全造成影響的權限,對于這部分權限,必須用戶動手點擊才可授權,
Android危險權限:

危險權限即作用
如果要使用以上危險權限,除了需要在AndroidManifest檔案中配置,還需要在代碼中對這些權限進行動態申請
7.2.2 在程式運行時申請權限
CALL_PHONE時撥打電話功能時需要的權限,是個危險權限,
撥打電話的邏輯:
private void call(){
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
接下來添加權限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.revise_7_1">
<uses-permission android:name="android.permission.CALL_PHONE"/>
...
</manifest>
如果在低于6.0的版本使用此方法撰寫打電話功能,是可以正常運行的,但在高于6.0的系統運行,會出錯,提示我們"Permission Denial",
對6.0后作出的修改:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第一步:判斷用戶是不是給過我們權限
//ContextCompat.checkSelfPermission接收兩個引數,第一個是背景關系,第二個是權限名
if(ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
//第二步:沒有授權就呼叫ActivityCompat.requestPermissions()方法來向用戶申請授權
//接收三個引數,第一個是背景關系,第二個是String[]陣列,把要申請的權限名放在陣列中,第三個是請求碼
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE},1);
}else
call();
}
//第三步:不管我們是否給予權限,都回呼到此方法中,授權結果封裝在grantResults引數中
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED)
call();
else
finish();
}
}
這樣動態添加權限后,程式就可正常運行,
7.3 訪問其他程式中的資料
內容URI
內容URI為內容提供器中的資料建立了唯一的識別符號,就是根據他知道要訪問那個資料,由兩部分組成:
authority:用于對不同的app做區分,一般寫法:包名.provider
path:用于對同一應用程式中不同的表做區分
為了看出這是URI還要加上頭部協議,標準格式如下
content://com.example.app.provider/table
還有一種常用格式
content://com.example.app.provider/table/ID
這種表示訪問com.example.app程式下table表中id為ID(int)的資料
創建自己的內容提供器
- 創建一個SQL資料庫
要使用內容提供器肯定需要程式中有SQL資料庫,可以用SQLiteDatabase創建,也可以用LitePal,不懂的點這里,我用LitePal創建了一個Demo庫,litepal.xml和Demo1表如下
<?xml version="1.0" encoding="UTF-8" ?>
<litepal>
<dbname value="demo"/>
<version value="1"/>
<list>
<mapping class="com.example.revise_sqlitedatabase.Demo1"></mapping>
</list>
</litepal>
package com.example.revise_sqlitedatabase;
import org.litepal.crud.LitePalSupport;
public class Demo1 extends LitePalSupport {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 創建自己的內容提供器
右擊包名->new->Other->ContentProvider

class name就是你的內容提供器的類名,URI Authorities就是URI的authority,一般寫成 包名.provider
MyContentProvider 要重寫6個方法
注意事項:
1.使用通配符匹配兩種格式的內容URI
| 符號 | 含義 |
|---|---|
| * | 匹配任意長度的任意字符 |
| # | 匹配任意長度的數字 |
例如:匹配表中的一行資料content://com.example.app.provider/table/#
2.UriMatcher類
UriMatcher類可看做匹配URI的工具類,addURI方法傳入authority,path,和一個自定義代碼當呼叫UriMatcher的match()方法時,可根據傳入的uri回傳相應的自定義代碼
用自定義代碼去判斷到底訪問的是那個表
3.Uri物件所對應的MIME型別
以vnd開頭
如果URI以路徑結尾,后接android.cursor.dir/,如果以id結尾,后接android.cursor.item/
最后接上vnd.authority.path
package com.example.revise_sqlitedatabase;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import org.litepal.LitePal;
public class MyContentProvider extends ContentProvider {
public static final int Demo1_DIR = 0; //訪問所有資料
public static final int Demo1_ITEM = 1; //訪問單條資料
public static final String AUTHORITY= "com.example.revise_sqlitedatabase.provider";
private static UriMatcher uriMatcher;
private Demo1 demo1;
SQLiteDatabase db;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY,"Demo1",Demo1_DIR);
uriMatcher.addURI(AUTHORITY,"Demo1/#",Demo1_ITEM);// #匹配數字
}
public MyContentProvider() {
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
//洗掉資料
int deletedRows = 0;
switch (uriMatcher.match(uri)){
case Demo1_DIR:
deletedRows = db.delete("Demo1",selection,selectionArgs); //回傳受影響的行數
break;
case Demo1_ITEM:
String Id = uri.getPathSegments().get(1);
//getPathSegments()方法吧URI權限后的部分以“/”分割,0位置是路徑,1位置是id
deletedRows = db.delete("Demo1","id = ?",new String[]{Id});
break;
default:
break;
}
return deletedRows;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
case Demo1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.revise_sqlitedatabase.Demo1";
case Demo1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.revise_sqlitedatabase.Demo1";
default:
break;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//添加資料回傳的是新添加的資料的Uri
Uri uriReturn = null;
switch (uriMatcher.match(uri)){
case Demo1_DIR:
case Demo1_ITEM:
long newId = db.insert("Demo1",null,values);
uriReturn = Uri.parse("content://"+AUTHORITY+"/Demo1/"+newId);
break;
default:
break;
}
return uriReturn;
}
@Override
public boolean onCreate() {
//獲取SQLiteDatabase因為這些方法全是用SQLiteDatabase訪問資料庫的
db = LitePal.getDatabase();
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
//查詢資料回傳Cursor
Cursor cursor = null;
switch (uriMatcher.match(uri)){
case Demo1_DIR:
cursor = db.query("Demo1",projection,selection,selectionArgs,null,null,sortOrder);
break;
case Demo1_ITEM:
String Id = uri.getPathSegments().get(1);
cursor = db.query("Demo1",projection,"id = ?",new String[]{Id},null,null,sortOrder);
break;
default:
break;
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
//更新資料
int updatedRows = 0;
switch (uriMatcher.match(uri)){
case Demo1_DIR:
updatedRows = db.update("Demo1",values,selection,selectionArgs); //回傳受影響的行數
break;
case Demo1_ITEM:
String Id = uri.getPathSegments().get(1);
updatedRows = db.update("Demo1",values,"id = ?",new String[]{Id});
break;
default:
break;
}
return updatedRows;
}
}
使用現有的內容提供器來讀取和操作相應程式中的資料
訪問剛才的程式中的資料
Context中的getContentResolver()中提供了一系列方法用于對資料的CRUD
Uri uri = Uri.parse("content://com.example.revise_sqlitedatabase.provider/Demo1");
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.button1 :
//添加
ContentValues values = new ContentValues();
values.put("name","aaa");
values.put("age",17);
values.put("hight",70);
getContentResolver().insert(uri,values);
values.clear();
values.put("name","bbb");
values.put("age",19);
values.put("hight",100);
getContentResolver().insert(uri,values);
values.clear();
values.put("name","ccc");
values.put("age",21);
values.put("hight",180);
getContentResolver().insert(uri,values);
break;
case R.id.button2 :
//更新
ContentValues values1 = new ContentValues();
values1.put("age",9);
getContentResolver().update(uri,values1,"name = ?",new String[]{"aaa"});
break;
case R.id.button3 :
//洗掉
getContentResolver().delete(uri,"name = ?",new String[]{"bbb"});
break;
case R.id.button4 :
//查詢
Cursor cursor = null;
try{
cursor = getContentResolver().query(uri,null,null,null,null);
if(cursor != null){
while (cursor.moveToNext()){
Log.d("MainActivity",cursor.getString(cursor.getColumnIndex("name"))
+cursor.getInt(cursor.getColumnIndex("age")));
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(cursor != null){
cursor.close();
}
}
break;
case R.id.button5 :
break;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/85369.html
標籤:其他
上一篇:博客圖片
