日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内容提供器(Content-Provider)完整使用指南

發(fā)布時間:2025/3/19 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内容提供器(Content-Provider)完整使用指南 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

[TOC]

1. 什么是內(nèi)容提供器?

? 內(nèi)容提供器(Content Provider) 主要用于在不同的應用程序之間實現(xiàn)數(shù)據(jù)的共享功能,他提供了一套完整的機制,允許一個程序訪問另一個程序中的數(shù)據(jù),同時還可以保證被訪問的數(shù)據(jù)的安全性,目前使用內(nèi)容提供器十Android實現(xiàn)跨程序共享數(shù)據(jù)的標準方式. 內(nèi)容提供器可以選擇只對哪一部分的數(shù)據(jù)進行共享,這樣就可以保證我們數(shù)據(jù)的安全性.

?

2. 如何使用內(nèi)容提供器獲取其他應用的數(shù)據(jù)

2.1 權(quán)限聲明

? 運行時權(quán)限:6.0系統(tǒng)中引入的新功能,為了能更好的保護用戶的隱私.

? 通常的權(quán)限聲明只需要在MainFest中添加要使用的權(quán)限就可以了,6.0及以后對于某些權(quán)限還需要在運行的時候在代碼中檢測是否有這個權(quán)限否則彈出對話框申請,拒絕的話是無法使用的.

? **并不是所有的權(quán)限都需要用到運行時權(quán)限,只有關(guān)系到用戶隱私的才需要.除了在ManiFest中聲明以外,還要在代碼中重新請求一 遍,如果沒有使用運行時權(quán)限則會導致這個應用拋出異常SecurityException() **

?

public class MainActivity extends AppCompatActivity {private String TAG = "TAG";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);checkSelf();//檢查權(quán)限}private void checkSelf() {//如果檢查多個權(quán)限的話,可以將要檢查的權(quán)限放入數(shù)組或者集合當中,遍歷檢查即可if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {/*** 通過checkSelfPermission可以檢查當前這個應用有沒有獲取到指定的那個權(quán)限,沒有的話就調(diào)用請求權(quán)限的那個方法.* 根據(jù)返回值來判斷狀態(tài) 0表示權(quán)限已給予,-1表示沒有獲取到權(quán)限.*/Log.d(TAG, "checkSelf: 權(quán)限允許");} else {/*** 通過ActivityCompat.requestPermissions動態(tài)的申請權(quán)限.* 第一個參數(shù):當前的上下文* 第二個參數(shù):需要申請的權(quán)限的字符串,保存在數(shù)組中.* 第三個參數(shù):查詢碼,請求權(quán)限的最終結(jié)果會通過回調(diào)的方式->onRequestPermissionsResult();在這個方法中,告訴你最后請求成功了沒有*/ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CALENDAR,Manifest.permission.CAMERA}, 1);}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {/*** 通過請求碼來判斷具體是申請了什么權(quán)限,以及結(jié)果;* grantResult[] 保存著申請權(quán)限后,根據(jù)申請權(quán)限的先后順序保存*/switch (requestCode) {case 1:if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {Log.d(TAG, "onRequestPermissionsResult: 已授權(quán)");for (int i = 0; i < grantResults.length; i++) {Log.d(TAG, "onRequestPermissionsResult: 授權(quán)情況:"+grantResults[i]);}} else {Log.d(TAG, "onRequestPermissionsResult: 您拒絕了授權(quán)");}break;case 2:break;default:break;}} }復制代碼

?

? 以上就是運行時權(quán)限的基本用法

2.2 內(nèi)容提供器的基本用法及原理

? 內(nèi)容提供器的用法一般有兩種,一是使用現(xiàn)有的內(nèi)容提供器來讀取和操作相應程序中的數(shù)據(jù),二是自己創(chuàng)建一個內(nèi)容提供器給我們的程序的數(shù)據(jù)提供外部訪問接口 (就是通過別人(程序)提供的內(nèi)容提供器來獲取別人(程序)想要給我們使用的數(shù)據(jù)),系統(tǒng)自帶的短信,電話簿,媒體庫等程序都提供了類似的訪問接口,我們就可以利用這個來進行再次開發(fā)和使用了.

?

? 如果想要獲取內(nèi)容提供器中的數(shù)據(jù),那么就需要借助Content-Resolver類,Context中的GetContentResolver方法可以獲取到該類的實例. Content-Resolver提供了類似SqLiteDatabase類的方法,可以對共享的數(shù)據(jù)進行CRUD 操作,只是參數(shù)略微有點不同罷了.

? 內(nèi)容提供器是通過Uri來尋找數(shù)據(jù)源的 Uri由authority和path組成;authority用于區(qū)分不同的程序,通常使用包名,path是對同一程序不同的表做區(qū)分用的.

? 比如某個包名為 com.example.test 有兩張表table1,table2;

? 則標準的Uri格式為(://前面的內(nèi)容為協(xié)議):

? content://com.example.test/table1

? content://com.example.test/table2

? 這樣就可以明確的表達出我們想要訪問哪個程序的哪個表里面的數(shù)據(jù)了. 所以內(nèi)容提供器的CRUD都只接受Uri參數(shù)來確定位置.

查找:

Uri uri=Uri.parse("content://com.example.test/table2");

Cursor cursor=getContentResolver().quert(uri,projection,selection,selectionArgs,sortOrder);

quert()方法的參數(shù)對應SQL部分描述
urifrom table_name指定查詢某個應用程序下的某一張表
projectionselect column1,column2指定查詢的列名
selectionwhere column =value指定where的約束條件
selectionArgs-為where中的占位符提供具體的值
sortOrderorder by column1,column2指定查詢結(jié)果的排序方式

從cursor中取出值也和數(shù)據(jù)庫的操作一樣,選擇想要獲取的數(shù)據(jù)類型,再選擇列名即可得到

...String data=cursor.getString(cursor.getColumnIndex("columnName"));...復制代碼

插入:

? 和數(shù)據(jù)庫的操作差不多,都是講數(shù)據(jù)組裝到ContentValues中

ContentValues values=new ContentValues();values.put("columnName1","value1");values.put("columnName2","value2");getContentResolver().insert(uri,values); 復制代碼

更新:

ContentValues values=new ContentValues(); values.put("columnName1","value1"); getContentResolver().update(Uri.parse(""),contentValues,"where column1=?",new String[]{"1"}); 復制代碼

update()中的參數(shù)解釋:第一個參數(shù)指定數(shù)據(jù)的位置;第二個參數(shù)指定要更新成什么值;第三個參數(shù)指定條件;第四個參數(shù)指定where條件語句中的缺省值;

刪除:

?

getContentResolver().delete(Uri.parse(""),"column=?",new String[]{"1"}); 復制代碼

? 參數(shù)的意思和上面幾個差不多.就不過多的解釋了.

2.3 使用內(nèi)容提供器獲取數(shù)據(jù)

? 下面使用系統(tǒng)已經(jīng)給我們提供好了的內(nèi)容提供器來獲取通訊簿中的姓名的電話號碼吧,先確保的確保存了幾個電話號碼在通訊簿中.

1.首先需要獲取READ_CANTACTS權(quán)限否則是不能讀取數(shù)據(jù)的 并且會報錯.

2.查詢語句和數(shù)據(jù)庫的用法相似

public class MainActivity extends AppCompatActivity {private String TAG = "TAG";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 1);} else {getData();}}private void getData() {Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);//傳入的Uri是ContactsContract.CommonData-Kinds.Phone類已經(jīng)幫我們封裝好了的一個常量//點開源代碼可以看到 : //public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,"phones");if (cursor != null) {while (cursor.moveToNext()) {String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));//ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME 也是一個常量,為保存該數(shù)據(jù)的類名.下同String phone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));Log.d(TAG, "getData: " + name + "-" + phone);}}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {switch (requestCode) {case 1:if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {getData();} else {Log.d(TAG, "onRequestPermissionsResult: 你點擊了拒絕!");}break;default:break;}} }復制代碼

運行程序就可以看到姓名和電話一起打印出來了.

主要的內(nèi)容都在getData();方法中,具體的解釋都寫在注釋中,只要知道原理 那么使用起來就變得十分的方便了.

3. 創(chuàng)建自己的內(nèi)容提供器

基礎(chǔ)知識:

通過新建一個類去繼承ContentProvider的方式來創(chuàng)建一個內(nèi)容提供器,但是必須重寫里面的六個方法;

?

重寫的方法:返回值用途
onCreate();boolean初始化內(nèi)容提供器的時候調(diào)用.通常會在這里完成對數(shù)據(jù)庫的創(chuàng)建和升級操作.返回true表明內(nèi)容提供器初始化成功,false失敗.
query(uri,projection, selection, selectionArgs, sortOrder);Cursor從內(nèi)容提供器中查找數(shù)據(jù),使用uri參數(shù)來確定要查找哪一張表格,projection用于確定查找哪些列,selection用于確定查找的條件,selectionArgs用于填充selection中的條件的缺省值,sortOrder用于對查詢結(jié)果排序 ; 查詢結(jié)果放入Cursor中返回;
insert(uri, values);Uri向內(nèi)容提供器中添加一條數(shù)據(jù),使用uri來確定要添加到的表,待添加的數(shù)據(jù)放在values參數(shù)中; 添加成功以后 返回一個用于表示這條新紀錄的Cursor;
update(uri, values, selection, selectionArgs);int更新內(nèi)容提供器中已有的數(shù)據(jù),使用Uri參數(shù)來確定更新哪一張表中的數(shù)據(jù),新的數(shù)據(jù)保存在values中(只更新這里有寫出來的值),selection和selectIonArgs參數(shù)用于約束更新哪些行;受影響的行數(shù)將作為返回值 返回
delete(uri, selection, selectionArgs)int刪除內(nèi)容提供器中的數(shù)據(jù),uri參數(shù)用來確定刪除哪張表中的數(shù)據(jù),selection和selectionArgs參數(shù)用于約束刪除哪些行;被刪除的行數(shù)將作為返回值返回;
getType(uri)();String根據(jù)傳入的Uri來返回相對應的MIME類型字符串

Uri兩種格式的說明:

? content://com.example.test/table1/1;

表示調(diào)用方期望訪問的是com.exampke.test應用里面表table1中id為1的數(shù)據(jù)

? content://com.example.test/table1;

表示調(diào)用方期望訪問的是com.exampke.test應用里面表table1的所有數(shù)據(jù)

不過通常都使用通配符的方式來匹配這兩種格式:

:表示匹配任意長度的數(shù)字

#* :表示匹配任意長度的字符

上面的內(nèi)容就可以寫成: content://com.example.test/* 或 content://com.example.test/table1/#

getType();返回數(shù)據(jù)說明

? content://com.example.test/table1/1;

? content://com.example.test/table1;

還是以上面這兩個為例子.

MIME字符串: 以vnd開頭 + . + android.cursor.dir/(或android.cursor.item/) + vnd. + AUTHORITY + . + PATH

? vnd.android.cursor.dir/vnd.com.example.test.table1;

? vnd.android.cursor.item/vnd.com.example.test.table1

3.1 創(chuàng)建的基本步驟

創(chuàng)建一個繼承自ContentProvider的類,并重寫里面的六個方法

其中內(nèi)容提供器必須在ManiFest.xml中進行注冊,否則無法使用

<providerandroid:name=".MyProvider" android:authorities="com.example.h.content_demo_provider"android:enabled="true"android:exported="true" /> 復制代碼

第一個參數(shù):類名

第二個參數(shù):通常使用包名來使用, 可以區(qū)分 不同的程序之間的內(nèi)容提供器

第三個參數(shù):啟用

第四個參數(shù):表示允許被其他的應用程序進行訪問

新建一個內(nèi)容提供器:

public class MyProvider extends ContentProvider {public static final int BOOK_DIT = 0;public static final int BOOK_ITEM = 1;public static final int CATEGORY_DIR = 2;public static final int CATEGORT_ITEM = 3;public static UriMatcher sUriMatcher;public static final String AUTHORITY = "com.example.h.content_demo_provider";private MyDatabaseHelper mMyDatabaseHelper;private SQLiteDatabase db;{sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);sUriMatcher.addURI(AUTHORITY, "book", BOOK_DIT);sUriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);sUriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);sUriMatcher.addURI(AUTHORITY, "category/#", CATEGORT_ITEM);//UriMatcher 可以匹配uri 通過調(diào)用他的match()方法 匹配到就會返回我們在上面添加uri時填入的第三個參數(shù)}@Override/*** 初始化內(nèi)容提供器的時候調(diào)用,通常會在這里完成對數(shù)據(jù)庫的創(chuàng)建和升級等操作* 返回true表示內(nèi)容提供器初始化成功,返回false則表示失敗.*/public boolean onCreate() {//對當前內(nèi)容提供器需要的資源進行初始化mMyDatabaseHelper = new MyDatabaseHelper(getContext(), "info.db", null, 1);db = mMyDatabaseHelper.getWritableDatabase();Log.d(TAG, "onCreate: 內(nèi)容提供器初始化完成");return true;}@Nullable@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable Stringselection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {//查詢方法,通過解析uri來判斷想要查詢哪個程序的哪個表.通過UriMatchder進行匹配 如果有就返回前面addUri()中填入的codeCursor cursor = null;switch (sUriMatcher.match(uri)) {case BOOK_DIT:cursor = db.query("book", projection, selection, selectionArgs, null, null,sortOrder);Log.d(TAG, "query: 查詢整個表" + cursor);return cursor;case BOOK_ITEM:String itemId = uri.getPathSegments().get(1);cursor = db.query("book", projection, "id=?", new String[]{itemId}, null, null,sortOrder);/*** .getPathSegments()它會將內(nèi)容URI權(quán)限之后的部分以 / 進行分割,并把分割后的結(jié)果放入到一個字符串列表中,* 返回的列表[0]存放的就是路徑,[1]存放的就是id*/return cursor;case CATEGORT_ITEM:String itemId2 = uri.getPathSegments().get(1);cursor = db.query("category", projection, "id=?", new String[]{itemId2}, null, null,sortOrder);return cursor;case CATEGORY_DIR:cursor = db.query("category", projection, selection, selectionArgs, null, null,sortOrder);return cursor;default:return cursor;}}@Nullable@Overridepublic String getType(@NonNull Uri uri) {switch (sUriMatcher.match(uri)) {case BOOK_DIT:return "vnd.android.cursor.dir/vnd.com.example.h.content_demo_provider.book";case BOOK_ITEM:return "vnd.android.cursor.item/vnd.com.example.h.content_demo_provider.book";case CATEGORT_ITEM:return "vnd.android.cursor.item/vnd.com.example.h.content_demo_provider.category";case CATEGORY_DIR:return "vnd.android.cursor.dir/vnd.com.example.h.content_demo_provider.category";default:return null;}}@Nullable@Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {Uri uriReturn = null;switch (sUriMatcher.match(uri)) {case BOOK_DIT:case BOOK_ITEM:long value = db.insert("book", null, values);uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + value);return uriReturn;//返回新插入行的行id,如果發(fā)生錯誤則返回-1case CATEGORT_ITEM:case CATEGORY_DIR:long value2 = db.insert("category", null, values);uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + value2);return uriReturn;default:return uriReturn;}}@Overridepublic int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[]selectionArgs) {int deleteRows = 0;switch (sUriMatcher.match(uri)) {case BOOK_DIT:deleteRows = db.delete("book", selection, selectionArgs);return deleteRows;case BOOK_ITEM:String itemId1 = uri.getPathSegments().get(1);deleteRows = db.delete("book", "id=?", new String[]{itemId1});return deleteRows;case CATEGORT_ITEM:String itemId2 = uri.getPathSegments().get(1);deleteRows = db.delete("category", "id=?", new String[]{itemId2});return deleteRows;case CATEGORY_DIR:deleteRows = db.delete("category", selection, selectionArgs);return deleteRows;default:return deleteRows;}}@Overridepublic int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable Stringselection, @Nullable String[] selectionArgs) {int updateRows = 0;switch (sUriMatcher.match(uri)) {case BOOK_DIT:updateRows = db.update("book", values, selection, selectionArgs);return updateRows;case BOOK_ITEM:String itemId1 = uri.getPathSegments().get(1);updateRows = db.update("book", values, "id=?", new String[]{itemId1});return updateRows;case CATEGORT_ITEM:String itemId2 = uri.getPathSegments().get(1);updateRows = db.update("category", values, "id=?", new String[]{itemId2});return updateRows;case CATEGORY_DIR:updateRows = db.update("category", values, selection, selectionArgs);return updateRows;default:return updateRows;}} }復制代碼

新出現(xiàn)的方法:

uri.getPathSegments().get(1); //getPathSegments()返回一個集合,它將uri中authority后面的內(nèi)容進行分割 即get(0)表名和id的值get(1) 這樣取出來的id就可以當作條件對數(shù)據(jù)庫進行條件查詢了 .

3.2 跨程序獲取數(shù)據(jù)

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private Button btn1, btn2, btn3, btn4;private Uri mUriBook = Uri.parse("content://com.example.h.content_demo_provider/book");private Uri mUriCategory = Uri.parse("content://com.example.h.content_demo_provider/category");@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();//randomInsert();iQuery();}private void initView() {btn1 = findViewById(R.id.button);btn2 = findViewById(R.id.button2);btn3 = findViewById(R.id.button4);btn4 = findViewById(R.id.button5);btn4.setOnClickListener(this);btn3.setOnClickListener(this);btn2.setOnClickListener(this);btn1.setOnClickListener(this);}private void iQuery() {Cursor cursor = getContentResolver().query(mUriBook, null, null, null, null);if (cursor != null) {while (cursor.moveToNext()) {String id = cursor.getString(cursor.getColumnIndex("id"));String name = cursor.getString(cursor.getColumnIndex("name"));String author = cursor.getString(cursor.getColumnIndex("author"));System.out.println(id + name + author);}} else {System.out.println("為空");}}private void randomInsert() {ContentValues contentValues1 = new ContentValues();ContentValues contentValues2 = new ContentValues();for (int i = 0; i < 5; i++) {contentValues1.put("name", "name" + i);contentValues1.put("author", "author" + i);System.out.println(getContentResolver().insert(mUriBook, contentValues1));contentValues2.put("type", "type" + i);contentValues2.put("code", "code" + i);System.out.println(getContentResolver().insert(mUriCategory, contentValues2)); ;}//這個方法只是通過內(nèi)容提供器對另一個程序中的數(shù)據(jù)庫寫一點數(shù)據(jù)進去方便我們進行后續(xù)的CRUD.}private void iDelete(String value) {ContentValues contentValues = new ContentValues();int x = 0;Uri uri = Uri.parse("content://com.example.h.content_demo_provider/book/" + value);x = getContentResolver().delete(uri, null, null);Log.d("TAG", "iDelete: 刪除后的返回值:" + x);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.button:iQuery();break;case R.id.button2:break;case R.id.button4:iDelete("1");break;case R.id.button5:break;default:break;}} } 復制代碼

? 主要還是通過定義好Uri 然后傳遞給內(nèi)容提供器,告訴它你想做什么,最后他會將執(zhí)行結(jié)果通過返回值告訴你,更新功能和其他幾個差不多就不展開解析了,

3.3 總結(jié)

經(jīng)過上面的實踐,給我的感覺就是, 某個程序A提供了一個內(nèi)容提供器(這個內(nèi)容提供器本質(zhì)上就是對本程序內(nèi)的數(shù)據(jù)庫進行CRUD 不過可以對他進行限制一些權(quán)限 只給想給的數(shù)據(jù)), 然后程序B想要訪問程序A中的某些數(shù)據(jù), 程序B可以通過Uri對程序A允許的范圍內(nèi)進行CRUD

總結(jié)

以上是生活随笔為你收集整理的内容提供器(Content-Provider)完整使用指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。