<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                Android四大組件之Content Provider **一、概念** Content Provider 作為Android應用程序四大組件之一,為存儲和查詢數據提供統一的接口,實現程序間數據的共享。Android系統內一些常見的數據如音樂、視頻、圖像等都內置了一系列的Content Provider。 ? ?? 應用程序間共享數據有兩種方式: 一是創建子類繼承于Content Provider,重寫該類用于數據存儲和查詢的方法。 二是直接使用已經存在的Content Provider,如聯系人等。 在Content Provider中數據的是以表的形式存儲,在數據表中每一行為一條記錄,每一列為類型和數據。每一條記錄都包括一個唯一的名叫_ID的數值字段,這個字段唯一標識一條數據記錄,在創建表的時候用 INTEGER?PRIMARY KEY AUTOINCREMENT來標識此字段。 ?????? **二、相關類介紹** **類URI:** 每一個Content Provider為其管理的多個數據集,分配一個URI,這個URI對外提供了一個能夠唯一標識自己數據集的字符串。這樣別的應用程序就可以通過這個URI來訪問這個數據集。Android中所有的Content Provider的URI都有固定格式:content://**開頭,一般可分為4個部分: **標準前綴:**用來標識一個Content Provider,固定Content:// **URI標識:**定義了是哪個Content Provider提供這些數據。一般是定義該ContentProvider的包類的名字。和AndroidManifest.xml中定義的authorities屬性相同。 **路徑:**標識URI下的某一個Item。 **記錄的ID:**如果URI中包含表示某個記錄的ID,則返貨該id對應的數據。否則表示返回全部。 注意:"content://com.android.people.provider/contacts/#" 這里#表示匹配任意數字"content://com.android.people.provider/contacts/*"表示匹配任意文本 **UriMatcher:**Uri標識了要操作的數據,而UriMatcher即使Android提供給我們用于操作Uri這個數據的工具類。 常用方法: ??????? public void addURI(String authority, String path, int code) 往UriMatcher對象里面添加Uri。 ??????? public int match(Uri uri)?與UriMatcher對象的Uri進行匹配,如果成功返回上面傳入的code值,否則返回-1. **類ContentUris:**類似于UriMatcher,也是一個操作Uri數據的工具類,用于在Uri后面追加一個ID或解析出傳入的Uri對象的ID值。 常用方法: ??????? public static Uri withAppendId(Uri contentUri, long id)? 為前面contentUri加上ID部分 ??????? public static long parseId(Uri contentUri)?從contentUri中獲取ID部分 **類ContentProvider:**常用方法: ~~~ public abstract boolean onCreate(); public abstract Uri insert(Uri uri, ContentValues values) public abstract int delete(Uri uri, String selection, String[] selectionArsg); public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs); public abstract Cursor query(Uri uri, String[] peojection, String selection, String[] selectionArgs, String sortOrder) public abstract String getType(Uri uri) ~~~ 這些都是抽象方法需要子類去實現。**類 ContentValues:** ?????? android.content.ContentValues 這個用于存儲ContentResolver能處理的數據的集合。 構造函數: ???????ContentValues()???????? // 創建一個空的ContentValues對象,初始化默認大小 ?????? ContentValues(int size) ?????? ContentValues(ContentValues from) 常用方法:???????? ~~~ void clear() boolean containKey(String key) Object get(String key) void put(String key, Type value) // Type: Byte Integer Float Short byte[] String Double Long Boolean int size() Type getAsTypeArray(String key) // Type: Object Boolean Byte byte[] Double Float Integer Long Short String ~~~ **類android.content.ContentResolver:** 一個程序可以通過實現一個ContentProvider的抽象接口將自己的數據以類似數據庫中表的方式完全暴露出去,那么外界其他應用程序怎么從數據庫中獲取數據呢,這就需要ContentResolver了,通過URI表示外界訪問需要的數據庫。???????????這個類為我們定義了一系列的方法包括:插入、刪除、修改、查詢等,與ContentProvider基本類似,主要根據傳入的參數Uri找到對應的Content Provider,調用其相應的方法。 構造函數: ??????? public ContentResolver(Context context) 一般在代碼中我們直接通過: MainActivity.this.getContentResolver()獲得當前應用程序的一個ContentResolver實例。?????? 這里我們需要考慮一個問題,就是如果多個程序同時通過ContentResolver共享訪問一個ContentProvider,會不會不同步,尤其是數據寫入的時候這就需要在AndroidManifest.xml中定義ContentProvider的時候加上:<provider>元素的multiprocess屬性。同時Android在ContentResolver中為我們提供了 notifyChange()接口,在數據發生改變時通知其他的ContentObserver。 ~~~ final void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer) final void unregisterContentObserver(ContentObserver observer) void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) void notifyChange(Uri uri, ContentObserver observer) ~~~ **三、使用已經存在的ContentProvider** 使用已經存在的ContentProvider包括兩種情況:一是從已經存在的ContentProvider里面讀取數據,如獲得 手機里面聯系人的信息。二是將自己的數據加入到ContentProvider里面,讓其他程序能共享次數據,這就需要獲得對這個 ContentProvider的寫權限了。 Android中電話簿就是通過ContentProvider實現數據共享的,系統中有很多已經存在的共享URI,我們可以使用ContentResolver通過Uri來操作不同的標的數據。如Contacts.People.CONTENT_URI 在Android中為我們提供了兩種方法來查詢Content Provider:一是使用ContentResolver的query()方法,二是使用Activity對象的manageQuery()方法,他們的參數都相同,而且都返回Cursor對象。但是使用manageQuery()方法返回的Cursor對象的生命周期自動被Activity來管理,被管理的Cursor對象在Activity進入暫停狀態的時候調用自己的deactivate()方法卸載,在Activity回到運行狀態的時候調用自己的requery()方法重新查詢生成的Cursor。而使用ContentResolver的query()方法返回的Cursor對象需要手動加入Activity來管理,這是通過Activity的startManagingCursor()方法來實現的。 **四、創建自己的ContentProvider** (1) 創建一個繼承于ContentProvider的類MyContentProvider (2) 定義一個public static final Uri 類型變量CONTENT_URI 如:public static final Uri CONTENT_URI = Uri.parse("content://com.android.MyContentProvider") (3) 定義需要返回給客戶端的數據列名,如果使用到數據庫SQLite,必須定義一個_id,表示記錄的唯一性。 (4) 創建數據存儲系統,如文件系統或數據庫SQLite系統。 (5) 如果存儲字節型數據,如位圖文件等,數據列其實是一個表示實際保存文件的URI字符串,用來讀取對應的實際文件數據。?處理這種數據類型的Content Provider需要實現一個名為_data的字段,該字段列出了該文件在Android系統的實際路?徑,客戶端可以通過調用方法ContentResolver. openOutputStream()來處理該URI指向的文件資源。 (6) 查詢返回一個Cursor類型對象,所有執行寫操作的方法如insert()、update()及delete()都將被監聽,可以通過Content Resolver().notifyChange()來通過監聽器關于數據更新的消息。 (7) 在AndroidManifest.xml中使用<provider>標簽來設置Content Provider信息,如:android:authorities、android:name android:permission等。 **Demo:** **數據庫類DatabaseHelper用來存儲個人信息,名字(name)對應年齡(age)** ~~~ public class DatabaseHelper extends SQLiteOpenHelper { private static final String DB_NAME = "personInfo.db"; private static final String TB_NAME = "person"; private static final int VERSION = 1; private static final String creat_cmd = "create table IF NOT EXISTS " + TB_NAME + " (_id integer PRIMARY KEY autoincrement, name text, age integer)"; private static final String upgrade_cmd = "alert table " + TB_NAME + " add sex varchar(8)"; public DatabaseHelper(Context context) { super(context, DB_NAME, null, VERSION); // TODO Auto-generated constructor stub } @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub db.execSQL(creat_cmd); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub db.execSQL(upgrade_cmd); } } ~~~ **創建自己的ContentProvider** ~~~ // 創建一個MyProvider繼承于ContentProvider public class MyProvider extends ContentProvider { private DatabaseHelper dbHelper; // 數據庫類 private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); private static final int ALL_PERSON = 1; private static final int PERSON = 2; private static final String TAG = "MyProvider"; private static final String TABLE_NAME = "person"; // 定義自己的URI private static final String AUTHORITY = "com.myAndroid.myProvider"; public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME); static { URI_MATCHER.addURI(AUTHORITY, "person", ALL_PERSON); URI_MATCHER.addURI(AUTHORITY, "person/#", PERSON); } // ContentProvider的入口,初始化 @Override public boolean onCreate() { // TODO Auto-generated method stub Log.i(TAG, "----onCreate----"); dbHelper = new DatabaseHelper(this.getContext()); return false; } @Override public int delete(Uri arg0, String arg1, String[] arg2) { // TODO Auto-generated method stub Log.i(TAG, "----delete----"); SQLiteDatabase db = dbHelper.getWritableDatabase(); int count = 0; switch (URI_MATCHER.match(arg0)) { case ALL_PERSON: count = db.delete(TABLE_NAME, arg1, arg2); case PERSON: long id = ContentUris.parseId(arg0); String where = "_id=" + id; if(arg1 != null && !"".equals(arg1)) { where += " and " + arg1; } count = db.delete(TABLE_NAME, where, arg2); default: throw new IllegalArgumentException("Unknown Uri:" + arg0.toString()); } getContext().getContentResolver().notifyChange(arg0, null); // 通知注冊客戶端數據發生改變 return count; } @Override public String getType(Uri arg0) { // TODO Auto-generated method stub Log.i(TAG, "----getType----"); switch (URI_MATCHER.match(arg0)) { case ALL_PERSON: return "com.android.cursor.dir/person"; case PERSON: return "com.android.cursor.item/person"; default: throw new IllegalArgumentException("Unknow Uri" + arg0.toString()); } } @Override public Uri insert(Uri uri, ContentValues arg1) { // TODO Auto-generated method stub Log.i(TAG, "----insert----"); SQLiteDatabase db = dbHelper.getWritableDatabase(); Uri insertUri = null; switch (URI_MATCHER.match(uri)) { case ALL_PERSON: long rowId = db.insert(TABLE_NAME, "name", arg1); Log.d(TAG, "insert:"+arg1.toString()+" Id:"+rowId); insertUri = ContentUris.withAppendedId(uri, rowId); // this.getContext().getContentResolver().notifyChange(insertUri, null); break; default: throw new IllegalArgumentException("Unknown Uri:" + uri.toString()); } getContext().getContentResolver().notifyChange(insertUri, null); return insertUri; } // 處理查詢,返回Cursor @Override public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { // TODO Auto-generated method stub Log.i(TAG, "----query----"); SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursir cursor = null; switch (URI_MATCHER.match(arg0)) { case ALL_PERSON: // query all the person info cursor = db.query(TABLE_NAME, arg1, arg2, arg3, null, null, arg4); case PERSON: // query only one person info from a given ID long id = ContentUris.parseId(arg0); String where = " _id=" + id; if( (!"".equals(arg2)) && (arg2 != null)) { where += " and " + arg2 ; } cursor = db.query(TABLE_NAME, arg1, where, arg3, null, null, arg4); default: throw new IllegalArgumentException("unknow uri" + arg0.toString()); } if(cursor != null) { // 注冊該Uri對應的數據發生改變時,向客戶端發送通知 cursor.setNotificationUri(getContext().getContentResolver(), uri); } return cursor; } @Override public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { // TODO Auto-generated method stub Log.i(TAG, "----update----"); SQLiteDatabase db = dbHelper.getWritableDatabase(); int count = 0; switch (URI_MATCHER.match(arg0)) { case ALL_PERSON: count = db.update(TABLE_NAME, arg1, arg2, arg3); break; case PERSON: long id = ContentUris.parseId(arg0); String where = "_id=" + id; if( (arg2 != null) && (!"".equals(arg2))) { where += " and " + arg2; } count = db.update(TABLE_NAME, arg1, where, arg3); break; default: throw new IllegalArgumentException("Unknow Uri:"+arg0.toString()); } getContext().getContentResolver().notifyChange(arg0, null); return count; } } ~~~ **客戶端使用Content Provider:** ~~~ // 定義自己的URI private static final String TABLE_NAME = "person"; private static final String AUTHORITY = "com.myAndroid.myProvider"; public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME); // 插入 ContentResolver contenResolver = MainActivity.this.getContentResolver(); ContentValues values = new ContentValues(); values.put("name", "hello"); values.put("age", 25); Uri resultUri = contentResolver.insert(CONTENT_URI, values); if(ContentUris.parseId(resultUri) > 0) { Log.i(TAG, "OK"); } // 查詢 String columns[] = new String[] ("_id", "name", "age"); Cursor cursor = contentResolver.query(CONTENT_URI, columns, null, null, "_id"); if(cursor.moveToFirst()) { do { Log.i(TAG, "_id:"+cursor.getInt(cursor.getColumnIndex("_id"))); Log.i(TAG, "name:"+cursor.getString(cursor.getColumnIndex("name"))); Log.i(TAG, "age:"+cursor.getInt(cursor.getColumnIndex("age"))); } while(cursor.moveToNext()); cursor.close(); } // 刪除 ID為1的記錄 contentResolver.update(Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME+"/1"), null, null); // 修改ID為 1 的記錄 ContentValues values = new ContentValues(); values.put("name", "world"); values.put("age", 32); contentResolver.update(Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME+"/1"), values, null, null); ~~~ 最后我們還需要在AndroidManifest.xml中定義我們的provider屬性: ~~~ <provider android:name=".MyProvider" android:authorities="com.myAndroid.myProvider" /> ~~~ **使用游標:** 這里我們關注下在query()方法中,我們查詢數據庫的時候使用到了一個Cursor對象,這個Cursor對象就是游標,它包含0個或多個記錄。列名稱、順序和類型都是特定于ContentProvider的,但是返回的每行都包涵啊一個名為_id的默認咧,表示該行的唯一ID。 ?1、游標是一個行集合 ? ?? ?2、讀取數據之前,需要使用moveToFirst()將游標移動到第一行之前 ?3、需要知道列名稱和列類型 ?4、所有字段的訪問都是基于列編號,所有必須首先將該列名稱轉換為列編號 ?5,、游標可以隨意移動(往前、往后,跳過一段距離等) 主要方法: ~~~ boolean moveToFirst() boolean isBeforeFirst() boolean isAfterLast() boolean isClosed() ~~~ **使用Where查詢:** 上面代碼中使用的manageQuery()的簽名為: public final Cursor manageQuery(Uri uri, String[] projectin, ?String selection, String[] selectionArgs, String sortOrder); 參數: Uri: 給定的URI projection: 聲明要返回的行屬性,傳遞null 返回給定URI的所有行 selection 表示過濾器,以SQL Where字句(不含Where本身)的格式聲明,可以使用?,將被替換為selectionArgs中的值,按照在列表中出現的順序顯示。 selectionArgs: 過濾器殘數 sortOrder: 排序方式 如:查詢id為23的筆記: ~~~ manageQuery("Content://com.google.provider.NotePad/notes/23", null, null, null, null); manageQuery("Content://com.google.provider.Notepad/notes", null, "_id=?", new String[] {23}, null); ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看