如何使用ContentProvider-簡介

如何使用ContentProvider-簡介

簡介

ContentProvider是一組讓你跟其他應用程式存取的資料庫
對於剛接觸的Android開發者來說
它會是一個比較難以上手的區域
Android提供一套通用的介面讓每個應用程式可以進行CRUD(新增、讀取、更新、刪除)的操作
ContentProvider用於管理音訊、影片、圖片、個人聯絡資訊等資料

ContentProvider處理流程

如果你要操作一個ContentProvider
可以透過繼承ContentProvider類別
就會看到以下的範例出現幾個方法必須實作

public class ContentProviderDemo extends ContentProvider{
    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Nullable
    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }
}

但是一般正常的作法是不會自己去實作的
ContentResovler類別是實作ContentProvider的子類別
通常會透過ContentResovler類別去操作已經實作CURD
一般你要操作它會使用它的四種方法query、insert、delete和update

final Cursor    query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
final Uri   insert(Uri url, ContentValues values)
final int   delete(Uri url, String where, String[] selectionArgs)
final int   update(Uri uri, ContentValues values, String where, String[] selectionArgs)

更多詳細方法可以參考
https://developer.android.com/reference/android/content/ContentResolver.html

存取ContentProvider記得要加入權限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

6.0以後的手機還要多加入RuntimePermission

private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
    //...
    ActivityCompat.requestPermissions(MainActivity.this,
        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
        MY_PERMISSIONS_REQUEST_READ_CONTACTS);
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            if (grantResults.length <= 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                finish();
            }
            return;
        }
    }
}

我們以第一個query方法來進行說明
可以看到第一個傳入的參數是Uri
Android提供了一套查詢ContentProvider的Uri
https://developer.android.com/reference/android/provider/package-summary.html

query() 引數SELECT 關鍵字/參數備註
UriFROM table_nameUri 會對應至供應程式中名為的「table_name」表格。
projectioncol,col,col,…projection 代表需針對每個擷取的資料列 納入的一系列資料欄。
selectionWHERE col = valueselection 會指定資料列選取條件。
selectionArgs(沒有任何相對應的關鍵字/參數。選取引數會取代選取子句中的 ? 預留位置。)
sortOrderORDER BY col,col,…sortOrder 會指定資料列在傳回的 Cursor 中的顯示順序。

查詢資料

透過ContentResolver來進行查詢手機內相簿的資料夾名稱

private void queryImageBucketNameData(){
    try {
        final String[] columns = {MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
        final String orderBy = MediaStore.Images.Media.DATE_ADDED;

        Cursor imagecursor = getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns,
                null, null, orderBy + " DESC");
        if (imagecursor != null && imagecursor.getCount() > 0) {

            while (imagecursor.moveToNext()) {
                int bucketColumn = imagecursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
                String bucket = imagecursor.getString(bucketColumn);
            }

        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

插入資料

將想要插入的資訊放入至ContentValues物件內就可以進行插入

Uri mNewUri;
ContentValues mNewValues = new ContentValues();
mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
mNewValues.put(UserDictionary.Words.WORD, "insert");
mNewValues.put(UserDictionary.Words.FREQUENCY, "100");

mNewUri = getContentResolver().insert(
    UserDictionary.Word.CONTENT_URI,   
    mNewValues
);

更新資料

如要更新資料列,請使用內含經過更新的值 (與您在插入資料時所使用的值相同) 以及選取條件 (與您在建立查詢時所使用的選取條件相同) 的 ContentValues 物件。 您所使用的用戶端方法為 ContentResolver.update()。您只需針對要更新的資料欄,將相關值加到 ContentValues 物件即可。 如果您想清除資料欄的內容,請將值設定為 null。

ContentValues mUpdateValues = new ContentValues();

String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
String[] mSelectionArgs = {"en_%"};
int mRowsUpdated = 0;
mUpdateValues.putNull(UserDictionary.Words.LOCALE);

mRowsUpdated = getContentResolver().update(
    UserDictionary.Words.CONTENT_URI,
    mUpdateValues
    mSelectionClause
    mSelectionArgs
);

刪除資料

刪除資料列的方法與擷取資料列資料類似:
您必須為想刪除的資料列指定選取條件,
用戶端方法最後會傳回已刪除的資料列數量。
以下程式碼片段可刪除應用程式 ID 為「user」的資料列。
此外,這個方法還會傳回已刪除的資料列數量。

String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
String[] mSelectionArgs = {"user"};
int mRowsDeleted = 0;
mRowsDeleted = getContentResolver().delete(
    UserDictionary.Words.CONTENT_URI,
    mSelectionClause
    mSelectionArgs
);

這樣就是一個簡單的ContentProvider操作了
更多詳細資訊可以參考官網
https://developer.android.com/guide/topics/providers/content-provider-basics.html?hl=zh-tw#SimpleQuery