您好,登錄后才能下訂單哦!
Android中ContentProvider組件如何使用,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
ContentProvider是Android系統中為開發者專門提供的不同應用間進行數據共享的組件,其提供了一套標準的接口用來獲取以及操作數據,準許開發者把自己的應用數據根據需求開放給其他應用進行增刪改查,而無須擔心直接開放數據庫權限而帶來的安全問題。系統預置了許多ContentProvider用于獲取用戶數據,例如消息、聯系人、日程表等。
具體形式如下圖所示:
在ContentProvider的使用過程中,需要借用ContentResolver來控制ContentProvider所暴露處理的接口,作為代理來間接操作ContentProvider以獲取數據。
在 Context.java 的源碼中如下抽象方法
/** Return a ContentResolver instance for your application's package. */ public abstract ContentResolver getContentResolver();
所以可以在所有繼承Context的類中通過 getContentResovler() 方法獲取ContentResolver
ContentResolver contentResolver = getContentResovler();
ContentProvider作為Android四大組件之一,并沒有Activity那樣復雜的生命周期,只有簡單地onCreate過程。
創建一個自定義ContentProvider的方式是繼承ContentProvider類并實現其六個抽象方法:
/** * @author: 下碼看花 * date: 2019/8/8 * description: ContentProvider例子 */public class MyContentProvider extends ContentProvider { /** * 執行初始化工作 * @return */ @Override public boolean onCreate() { return false; } /** * 查詢數據 * @param uri * @param projection * @param selection * @param selectionArgs * @param sortOrder * @return */ @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { return null; } /** * 通過Uri返回對應的MIME類型 * @param uri * @return */ @Override public String getType(@NonNull Uri uri) { return null; } /** * 插入新數據 * @param uri * @param values * @return */ @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { return null; } /** * 刪除已有數據 * @param uri * @param selection * @param selectionArgs * @return */ @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; } /** * 更新數據 * @param uri * @param values * @param selection * @param selectionArgs * @return */ @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; } }
之后,需要在AdnroidManifest.xml中對ContentProvider進行注冊
<!-- xxx為上一層包名 --><provider android:name=".MyContentProvider" android:authorities="com.xmkh.MyContentProvider" android:exported="true"/>
name:自定義的ContentProvider的全稱類名。
authorities:自定義ContentProvider的唯一標識,外部應用通過該屬性值來訪問我們的ContentProvider。因此該屬性值必須是唯一的,建議在命名時以包名為前綴。
exported:表明是否允許其他應用調用ContentProvider,true表示支持,false表示不支持。默認值根據開發者的屬性設置而會有所不同,如果包含 Intent-Filter 則默認值為true,否則為false。
觀察MyContentProvider中的幾個方法,可以發現除了 onCreate() 方法外,其它五個抽象方法都包含了一個Uri(統一資源標識符)參數,通過這個對象可以來匹配對應的請求。那么從ContentProvider的數據操作方法可以看出都依賴于Uri,而對于Uri有其固定的數據格式,例如:
比如,ContentProvider中操作的數據可以都是從SQLite數據庫中獲取的,而數據庫中可能存在許多張表,這時候就需要用到Uri來表明是要操作哪個數據庫、操作數據庫的哪張表了
/** * @author: 下碼看花 * date: 2019/8/8 * description: URI組裝代碼示例 */public class TestContract { public static final String CONTENT_AUTHORITY = "com.xmkh.contentproviderdemo.MyContentProvider"; public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); public static final String PATH_ARTICLE = "article"; public static final class TestEntry implements BaseColumns { public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_ARTICLE).build(); protected static Uri buildUri(long id) { return ContentUris.withAppendedId(CONTENT_URI, id); } protected static final String TABLE_NAME = "article"; public static final String COLUMN_NAME = "name"; } }
從上面代碼我們可以看到,我們創建了一個 content://com.xmkh.contentproviderdemo.MyContentProvider/article
的uri,并且開了一個靜態方法,用以在有新數據產生時根據id生成新的Uri。
那么如何確定一個Uri是要執行哪項操作呢?這里需要用到UriMatcher來幫助ContentProvider匹配Uri,它僅包含了兩個方法:
addURI(String authority, String path, int code):用于向UriMatcher對象注冊Uri。authtity是在AndroidManifest.xml中注冊的ContentProvider的authority屬性值;path表示一個路徑,可以設置為通配符,#表示任意數字,*表示任意字符;兩者組合成一個Uri,而code則代表該Uri對應的標識碼
match(Uri uri):匹配傳入的Uri。返回addURI()方法中傳遞的code參數,如果找不到匹配的標識碼則返回-1
講了這么多,相信大家已經有一個初步的了解,為了讓我們加深記憶,跟我一起寫一個demo吧!
首先,自定義一個ContentProvider,然后向其寫入和讀取數據,使用SQLite作為ContentProvider的數據存儲地址和數據來源,因此需要先建立一個SQLiteOpenHelper,創建一個名為"article.db"的數據庫,包含“article”和“author”兩張表:
/** * @author: 下碼看花 * date: 2019/8/8 * description: 演示demo數據庫 */public class DbOpenHelper extends SQLiteOpenHelper { /** * 數據庫名 */ private static final String DATA_BASE_NAME = "article.db"; /** * 數據庫版本號 */ private static final int DATE_BASE_VERSION = 1; /** * 表名-文章 */ public static final String ARTICLE_TABLE_NAME = "article"; /** * 表名-作者 */ public static final String AUTHOR_TABLE_NAME = "author"; /** * 創建表-文章(兩列:主鍵自增長、文章名稱) */ private final String CREATE_ARTICLE_TABLE = "create table " + ARTICLE_TABLE_NAME + "(_id integer primary key autoincrement, articleName text)"; /** * 創建表-作者(三列:主鍵自增長、作者名、性別) */ private final String CREATE_AUTHOR_TABLE = "create table " + AUTHOR_TABLE_NAME + "(_id integer primary key autoincrement, authorName text, sex text)"; public DbOpenHelper(Context context) { super(context, DATA_BASE_NAME, null, DATE_BASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_ARTICLE_TABLE); db.execSQL(CREATE_AUTHOR_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
自定義ContentProvider 當中,getTableName(Uri uri)方法用于判定Uri指向的數據庫表名 然后在initProviderData()方法中向數據庫插入一些原始數據
為了方便大家理解,我們將上述出現的代碼進行修改,展示給大家:
/** * @author: 下碼看花 * date: 2019/8/8 * description: ContentProvider例子 */public class MyContentProvider extends ContentProvider { private Context mContext; private SQLiteDatabase sqLiteDatabase; public static final String AUTHORITY = "com.xmkh.MyContentProvider"; public static final int ARTICLE_URI_CODE = 0; public static final int AUTHOR_URI_CODE = 1; private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { uriMatcher.addURI(AUTHORITY, DbOpenHelper.ARTICLE_TABLE_NAME, ARTICLE_URI_CODE); uriMatcher.addURI(AUTHORITY, DbOpenHelper.AUTHOR_TABLE_NAME, AUTHOR_URI_CODE); } private String getTableName(Uri uri) { String tableName = null; switch (uriMatcher.match(uri)) { case ARTICLE_URI_CODE: tableName = DbOpenHelper.ARTICLE_TABLE_NAME; break; case AUTHOR_URI_CODE: tableName = DbOpenHelper.AUTHOR_TABLE_NAME; break; } return tableName; } public MyContentProvider() { } /** * 執行初始化工作 * * @return */ @Override public boolean onCreate() { mContext = getContext(); initArticleProviderData(); return false; } //初始化原始數據 private void initArticleProviderData() { sqLiteDatabase = new DbOpenHelper(mContext).getWritableDatabase(); sqLiteDatabase.beginTransaction(); ContentValues contentValues = new ContentValues(); contentValues.put("articleName", "Android四大組件之Activity"); sqLiteDatabase.insert(DbOpenHelper.ARTICLE_TABLE_NAME, null, contentValues); contentValues.put("articleName", "Android四大組件之BroadcastReceiver"); sqLiteDatabase.insert(DbOpenHelper.ARTICLE_TABLE_NAME, null, contentValues); contentValues.put("articleName", "Android四大組件之Service"); sqLiteDatabase.insert(DbOpenHelper.ARTICLE_TABLE_NAME, null, contentValues); contentValues.clear(); contentValues.put("authorName", "ptt"); contentValues.put("sex", "女"); sqLiteDatabase.insert(DbOpenHelper.AUTHOR_TABLE_NAME, null, contentValues); contentValues.put("authorName", "HiYoung"); contentValues.put("sex", "男"); sqLiteDatabase.insert(DbOpenHelper.AUTHOR_TABLE_NAME, null, contentValues); contentValues.put("authorName", "gy"); contentValues.put("sex", "男"); sqLiteDatabase.insert(DbOpenHelper.AUTHOR_TABLE_NAME, null, contentValues); sqLiteDatabase.setTransactionSuccessful(); sqLiteDatabase.endTransaction(); } /** * 查詢數據 * * @param uri * @param projection * @param selection * @param selectionArgs * @param sortOrder * @return */ @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { String tableName = getTableName(uri); if (tableName == null) { throw new IllegalArgumentException("Unsupported URI:" + uri); } return sqLiteDatabase.query(tableName, projection, selection, selectionArgs, null, null, sortOrder, null); } /** * 通過Uri返回對應的MIME類型 * * @param uri * @return */ @Override public String getType(@NonNull Uri uri) { return null; } /** * 插入新數據 * * @param uri * @param values * @return */ @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { String tableName = getTableName(uri); if (tableName == null) { throw new IllegalArgumentException("Unsupported URI:" + uri); } sqLiteDatabase.insert(tableName, null, values); mContext.getContentResolver().notifyChange(uri, null); return uri; } /** * 刪除已有數據 * * @param uri * @param selection * @param selectionArgs * @return */ @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { String tableName = getTableName(uri); if (tableName == null) { throw new IllegalArgumentException("Unsupported URI:" + uri); } int count = sqLiteDatabase.delete(tableName, selection, selectionArgs); if (count > 0) { mContext.getContentResolver().notifyChange(uri, null); } return count; } /** * 更新數據 * * @param uri * @param values * @param selection * @param selectionArgs * @return */ @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { String tableName = getTableName(uri); if (tableName == null) { throw new IllegalArgumentException("Unsupported URI:" + uri); } int row = sqLiteDatabase.update(tableName, values, selection, selectionArgs); if (row > 0) { mContext.getContentResolver().notifyChange(uri, null); } return row; } }
ContentProvider創建好切記一定要在AndroidManifest.xml中注冊!(前文已經提到了如何注冊,我就不再復述啦~)
然后分別操作article和author兩張表,向其插入一條數據后Log輸出所有的數據
/** * @author: 下碼看花 * date: 2019/8/8 * description: ContentProvider實戰 */public class MainActivity extends AppCompatActivity { private final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Uri articleUri = Uri.parse("content://com.xmkh.MyContentProvider/article"); ContentValues contentValues = new ContentValues(); contentValues.put("articleName", "Android四大組件之ContentProvider"); getContentResolver().insert(articleUri, contentValues); Cursor articleCursor = getContentResolver().query(articleUri, new String[]{"_id", "articleName"}, null, null, null); if (articleCursor != null) { while (articleCursor.moveToNext()) { Log.e(TAG, "ID:" + articleCursor.getInt(articleCursor.getColumnIndex("_id")) + " ArticleName:" + articleCursor.getString(articleCursor.getColumnIndex("articleName"))); } articleCursor.close(); } Uri authorUri = Uri.parse("content://com.xmkh.MyContentProvider/author"); contentValues.clear(); contentValues.put("authorName", "Austen"); contentValues.put("sex", "男"); getContentResolver().insert(authorUri, contentValues); Cursor authorCursor = getContentResolver().query(authorUri, new String[]{"_id", "authorName", "sex"}, null, null, null); if (authorCursor != null) { while (authorCursor.moveToNext()) { Log.e(TAG, "ID:" + authorCursor.getInt(authorCursor.getColumnIndex("_id")) + " AuthorName:" + authorCursor.getString(authorCursor.getColumnIndex("authorName")) + " Sex:" + authorCursor.getString(authorCursor.getColumnIndex("sex"))); } authorCursor.close(); } } }
得到的輸出結果是:
關于Android中ContentProvider組件如何使用問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。