預(yù)熱:動態(tài)申請權(quán)限
- 調(diào)用
checkSelfPermission(String permission)方法檢查是否具有權(quán)限 - 復(fù)寫
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)方法,來確認進入權(quán)限界面返回后是否獲取到了對應(yīng)權(quán)限。 - 本文中,想要獲取到聯(lián)系人的內(nèi)容,則需要動態(tài)獲取
Manifest.permission.CALL_PHONE的權(quán)限,同時Manifest里面要注冊該權(quán)限。
SampleCode
public class ContentProiderActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_proider);
if(checkPermission()){
//TODO do actions with permission
readContacts();
}else {
requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, 1);
}
}
private void readContacts() {
}
private boolean checkPermission(){
return checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts();
} else {
Log.w("lyh", "permission not granted");
}
break;
default:
break;
}
}
}
通過ContentResolver讀取數(shù)據(jù) (跨程序調(diào)用數(shù)據(jù))
ContentResolver其實是對于外部數(shù)據(jù)庫的一個封裝,可以通過其Provider提供的接口來實現(xiàn)對外部數(shù)據(jù)的增刪改查。
實現(xiàn)readContacts()具體功能:讀取所有聯(lián)系人姓名及其電話號碼
private void readContacts() {
Cursor cursor;
try {
cursor = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null , null, null, null);
if(cursor != null) {
//we get all contact info in this while loop, use this info to do further
while (cursor.moveToNext()) {
String contactName = cursor.getString(cursor.getColumnIndex
(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex
(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.i("lyh", "name = " + contactName + ", number = " + number);
}
}
} catch (RuntimeException e) {
e.printStackTrace();
}
}
創(chuàng)建ContentProvider供外部使用
1.總體使用方法(搭配前文的數(shù)據(jù)庫介紹的DBOpenHelper一起使用)
ContentProvider相當于對于創(chuàng)建的數(shù)據(jù)庫的對外部的一層封裝,外部應(yīng)用or模組想要對本數(shù)據(jù)庫進行操作的話,則必須通過ContentProvider來進行交互。ContentPorvider可以指定用戶可以訪問的uri,針對uri,在ContentPorvider里進行封裝好的處理動作,這樣就避免了敏感信息可以被外部訪問到,同時又把想要對外暴露的數(shù)據(jù)暴露了出來。
SampleCode, 這里僅針對query 進行了實現(xiàn)。其它幾個操作的流程是類似的
public class MyProvider extends ContentProvider {
public static final String AUTHORITY = "com.example.crane.myfirstline.provider";
public static final int BOOK_DIR = 0;
public static final int BOOK_ITEM = 1;
public static final int CATEGORY_DIR = 2;
public static final int CATEGORY_ITEM = 3;
public static final int DB_VERSION = 1;
private static UriMatcher uriMatcher;
private MyLibraryDBHelper dbHelper;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
// *:匹配任意長度任意字符
// #:匹配任意長度數(shù)字
uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
}
@Override
public boolean onCreate() {
dbHelper = new MyLibraryDBHelper(getContext(), "library.db", null, DB_VERSION);
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor c = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
//query all data in table1
c = db.query("book", projection, selection, selectionArgs, null, null, sortOrder);
break;
case BOOK_ITEM:
//query sigle data in table1
String bookId = uri.getPathSegments().get(1);
c = db.query("book", projection, "id = ?", new String[] {bookId}, null, null, sortOrder);
break;
case CATEGORY_DIR:
break;
case CATEGORY_ITEM:
break;
default:
break;
}
return c;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
return "vnd.android.cusor.dir/" + AUTHORITY + ".book";
case BOOK_ITEM:
return "vnd.android.cusor.item/" + AUTHORITY + ".book";
case CATEGORY_DIR:
return "vnd.android.cusor.dir/" + AUTHORITY + ".category";
case CATEGORY_ITEM:
return "vnd.android.cusor.item/" + AUTHORITY + ".category";
default:
break;
}
return null;
}
}
2.關(guān)于getType()方法的思考
Google給的注釋:
/**
* Implement this to handle requests for the MIME type of the data at the
* given URI. The returned MIME type should start with
* <code>vnd.android.cursor.item</code> for a single record,
* or <code>vnd.android.cursor.dir/</code> for multiple items.
* This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
* and Threads</a>.
*
* <p>Note that there are no permissions needed for an application to
* access this information; if your content provider requires read and/or
* write permissions, or is not exported, all applications can still call
* this method regardless of their access permissions. This allows them
* to retrieve the MIME type for a URI when dispatching intents.
*
* @param uri the URI to query.
* @return a MIME type string, or {@code null} if there is no type.
*/
public abstract @Nullable String getType(@NonNull Uri uri);
也就是說,通過返回這個MIME類型的字符串,可以判斷出來我們在使用ContentResolver進行查詢時,返回的cursor中含有多條或是單條數(shù)據(jù),可以優(yōu)化處理邏輯,提高效率;具體分析詳見下方連接
對ContentProvider中g(shù)etType方法的一點理解