九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
總結(jié)Content Provider的使用

總結(jié)Content Provider的使用

本帖最后由 feng_home 于 2010-8-14 08:15 編輯

Android中的Content provider機(jī)制可支持在多個應(yīng)用中存儲和讀取數(shù)據(jù)。這也是跨應(yīng)用共享數(shù)據(jù)的唯一方式。在android系統(tǒng)中,沒有一個公共的內(nèi)存區(qū)域,供多個應(yīng)用共享存儲數(shù)據(jù)。

Android提供了一些主要數(shù)據(jù)類型的Content provider,比如音頻、視頻、圖片和私人通訊錄等。可在android.provider包下面找到一些android提供的Content provider??梢垣@得這些Content provider,查詢它們包含的數(shù)據(jù),當(dāng)然前提是已獲得適當(dāng)?shù)淖x取權(quán)限。

如果想公開自己的數(shù)據(jù),那么可有兩種辦法:


  • 創(chuàng)建自己的Content provider,需要繼承ContentProvider類;
  • 如果你的數(shù)據(jù)和已存在的Content provider數(shù)據(jù)結(jié)構(gòu)一致,可以將數(shù)據(jù)寫到已存在的Content provider中,當(dāng)然前提是獲取寫該Content provider的權(quán)限。比如把OA中的成員通訊信息加入到系統(tǒng)的聯(lián)系人Content provider中。
Content provider基礎(chǔ)所有Content provider都需要實現(xiàn)相同的接口用于查詢Content provider并返回數(shù)據(jù),也包括增加、修改和刪除數(shù)據(jù)。首先需要獲得一個ContentResolver的實例,可通過Activity的成員方法getContentResovler()方法:
  1. ContentResolver cr = getContentResolver();
復(fù)制代碼

ContentResolver實例帶的方法可實現(xiàn)找到指定的Content provider并獲取到Content provider的數(shù)據(jù)。ContentResolver的查詢過程開始,Android系統(tǒng)將確定查詢所需的具體Content provider,確認(rèn)它是否啟動并運(yùn)行它。android系統(tǒng)負(fù)責(zé)初始化所有的Content provider,不需要用戶自己去創(chuàng)建。實際上,content provider的用戶都不可能直接訪問到content provider實例,只能通過ContentResolver在中間代理。數(shù)據(jù)模型Content provider展示數(shù)據(jù)類似一個單個數(shù)據(jù)庫表。其中:
  • 每行有個帶唯一值的數(shù)字字段,名為_ID,可用于對表中指定記錄的定位;
  • Content provider返回的數(shù)據(jù)結(jié)構(gòu),是類似JDBC的ResultSet,在android中,是Cursor對象。
URI每個content provider定義一個唯一的公開的URI,用于指定到它的數(shù)據(jù)集。一個content provider可以包含多個數(shù)據(jù)集(可以看作多張表),這樣,就需要有多個URI與每個數(shù)據(jù)集對應(yīng)。這些URI要以這樣的格式開頭:
  1. content://
復(fù)制代碼

表示這個uri指定一個content provider。如果你想創(chuàng)建自己的content provider,最好把自定義的URI設(shè)置為類的常量,這樣簡化別人的調(diào)用,并且以后如果更新URI也很容易。android定義了CONTENT_URI常量用于URI,比如:
  1. android.provider.Contacts.Phones.CONTENT_URI
  2. android.provider.Contacts.Photos.CONTENT_URI
復(fù)制代碼

要注意的是上面例子中的Contacts,已經(jīng)在android 2.0及以上版本不贊成使用。查詢Content provider要想使用一個content provider,需要以下信息:
  • 定義這個content provider的URI
  • 返回結(jié)果的字段名稱
  • 這些字段的數(shù)據(jù)類型
如果需要查詢content provider數(shù)據(jù)集的特定記錄(行),還需要知道該記錄的ID的值。構(gòu)建查詢查詢就是輸入URI等參數(shù),其中URI是必須的,其他是可選的,如果系統(tǒng)能找到URI對應(yīng)的content provider將返回一個Cursor對象??梢酝ㄟ^ContentResolver.query()或者Activity.managedQuery()方法。兩者的方法參數(shù)完全一樣,查詢過程和返回值也是相同的。區(qū)別是,通過Activity.managedQuery()方法,不但獲取到Cursor對象,而且能夠管理Cursor對象的生命周期,比如當(dāng)Activity暫停(pause)的時候,卸載該Cursor對象,當(dāng)Activity restart的時候重新查詢。另外,也可以對一個沒有處于Activity管理的Cursor對象做成被Activity管理的,通過調(diào)用Activity.startManaginCursor()方法。類似這樣:
  1. Cursor cur = managedQuery(myPerson, null, null, null, null);
復(fù)制代碼

其中第一個參數(shù)myPerson是Uri類型實例。如果需要查詢的是指定行的記錄,需要用_ID值,比如ID值為23,URI將是類似:
  1. content://. . . ./23
復(fù)制代碼

android提供了方便的方法,讓開發(fā)者不需要自己拼接上面這樣的URI,比如類似:
  1. Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
復(fù)制代碼

或者:
  1. Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
復(fù)制代碼

二者的區(qū)別是一個接收整數(shù)類型的ID值,一個接收字符串類型。其他幾個參數(shù):
  • names,可以為null,表示取數(shù)據(jù)集的全部列,或者聲明一個String數(shù)組,數(shù)組中存放列名稱,比如:People._ID。一般列名都在該Content provider中有常量對應(yīng);
  • 針對返回結(jié)果的過濾器,格式類似于SQL中的WHERE子句,區(qū)別是不帶WHERE關(guān)鍵字,如果返回null表示不過濾,比如name=?;
  • 前面過濾器的參數(shù),是String數(shù)組,是針對前面條件中?占位符的值;
  • 排序參數(shù),類似SQL的ORDER BY字句,不過不需要寫ORDER BY部分,比如name desc,如果不排序,可輸入null。
返回值是Cursor對象,游標(biāo)位置在第一條記錄之前。下面實例適用于android 2.0及以上版本,從android通訊錄中得到姓名字段:
  1. Cursor cursor = getContentResolver().query(
  2.         ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
  3.         null,
  4.         null);
復(fù)制代碼

返回值的內(nèi)容
_ID _COUNT NAME NUMBER
44 3 Alan Vain 212 555 1234
13 3 Bully Pulpit 425 555 6677
53 3 Rex Cars 201 555 4433

返回值的內(nèi)容類似上圖,不同的content provider會有不同的列和名稱,但是會有兩個相同的列,上面提到過的一個是_ID,用于唯一標(biāo)識記錄,還有一個_COUNT,用于記錄整個結(jié)果集的大小,可以看到上面圖中的_COUNT的值是相同的。讀取返回的數(shù)據(jù)如果在查詢的時候使用到ID,那么返回的數(shù)據(jù)只有一條記錄。在其他情況下,一般會有多條記錄。和JDBC的ResultSet類似,需要操作游標(biāo)遍歷結(jié)果集,在每行,再通過列名獲取到列的值,可以通過getString()、getInt()、getFloat()等方法獲取值。比如類似下面:
  1. while (cursor.moveToNext()) {
  2.     builder
  3.             .append(
  4.                     cursor
  5.                             .getString(cursor
  6.                                     .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)))
  7.             .append("-");
  8. }
復(fù)制代碼

和JDBC中不同,沒有直接通過列名獲取列值的方法,只能先列名獲取到列的整型索引值,然后再通過該索引值定位獲取列的值。編輯數(shù)據(jù)可以通過content provider實現(xiàn)以下編輯功能
  • 增加新的記錄;
  • 在已經(jīng)存在的記錄中增加新的值;
  • 批量更新已經(jīng)存在的多個記錄;
  • 刪除記錄。
所有的編輯功能都是通過ContentResolver的方法實現(xiàn)。一些Content provider對權(quán)限要求更嚴(yán)格一些,需要寫的權(quán)限,如果沒有會報錯。增加記錄要想增加記錄到content provider,首先,要在ContentValues對象中設(shè)置類似map的鍵值對,在這里,鍵的值對應(yīng)content provider中的列的名字,鍵值對的值,是對應(yīng)列希望的類型。然后,調(diào)用ContentResolver.insert()方法,傳入這個ContentValues對象,和對應(yīng)Content provider的URI即可。返回值是這個新記錄的URI對象。這樣你可以通過這個URI獲得包含這條記錄的Cursor對象。比如:
  1. ContentValues values = new ContentValues();

  2. values.put(People.NAME, "Abraham Lincoln");

  3. Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
復(fù)制代碼

在原有記錄上增加值如果記錄已經(jīng)存在,可在記錄上增加新的值,或者編輯已經(jīng)存在的值。首先要過去到原來的值對象,然后要清除原有的值,然后像上面增加記錄一樣即可:
  1. Uri uri=Uri.withAppendedPath(People.CONTENT_URI, "23");

  2. Uri phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);

  3. values.clear();
  4. values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
  5. values.put(People.Phones.NUMBER, "1233214567");
  6. getContentResolver().insert(phoneUri, values);
復(fù)制代碼

批量更新值批量更新一組記錄的值,比如NY改名為Eew York??烧{(diào)用ContenResolver.update()方法。刪除記錄如果是刪除單個記錄,調(diào)用ContentResolver.delete()方法,URI參數(shù),指定到具體行即可。如果是刪除多個記錄,調(diào)用ContentResolver.delete()方法,URI參數(shù)指定Content provider即可,并帶一個類似SQL的WHERE子句條件。這里和上面類似,不帶WHERE關(guān)鍵字。創(chuàng)建自己的Content provider創(chuàng)建content provider,需要:
  • 設(shè)置存儲系統(tǒng)。大多數(shù)content provider使用文件或者SQLite數(shù)據(jù)庫,不過你可以用任何方式存儲數(shù)據(jù)。android提供SQLiteoOpenHelper幫助開發(fā)者創(chuàng)建和管理SQLiteDatabase。
  • 繼承ContentProvider,提供對數(shù)據(jù)的訪問。
  • 在manifest文件中聲明content provider。
繼承ContentProvider類必須定義ContentProvider類的子類,需要實現(xiàn)如下方法:query()
insert()
update()
delete()
getType()
onCreate()query()方法,返回值是Cursor實例,用于迭代請求的數(shù)據(jù)。Cursor是一個接口。android為該接口提供了一些只讀的(和JDBC的ResultSet不一樣,后者還提供可寫入的可選特性)Cursor實現(xiàn)。比如SQLiteCursor,可迭代SQLite數(shù)據(jù)庫中的數(shù)據(jù)。可以通過SQLiteDatabase類的query()方法獲取到該Cursor實例。還有其他的Cursor實現(xiàn),比如MatrixCursor,用于數(shù)據(jù)不是存儲在數(shù)據(jù)庫的情況下。因為Content provider可能被多個ContentResolver對象在不同的進(jìn)程和線程中調(diào)用,因此實現(xiàn)Content provider必須考慮線程安全問題。作為良好的習(xí)慣,在實現(xiàn)編輯數(shù)據(jù)的代碼中,要調(diào)用ContentResolver.notifyChange()方法,通知那些監(jiān)聽數(shù)據(jù)變化的監(jiān)聽器。在實現(xiàn)子類的時候,還有一些步驟可以簡化Content provider客戶端的使用:定義public static final Uri常量,名稱為CONTENT_URI:
  1. public static final Uri CONTENT_URI =
  2.                Uri.parse("content://com.example.codelab.transportationprovider");
復(fù)制代碼

如果有多個表,它們也是使用相同的CONTENT_URI,只是它們的路徑部分不同。
也就是說紅色框部分是一致的。定義返回的列名,public static final,列名的值,比如使用SQLite數(shù)據(jù)庫作為存儲,對應(yīng)表的列名。在文檔中要寫出各個列的數(shù)據(jù)類型,便于使用者讀取。如果需要處理新的MIME數(shù)據(jù)類型,比如通過Intent的方式,并且?guī)ata的mimeType,那么需要在ContentProvider.getType()方法中進(jìn)行處理。聲明Content Provider創(chuàng)建Content Provider后,需要在manifest文件中聲明,android系統(tǒng)才能知道它,當(dāng)其他應(yīng)用需要調(diào)用該Content Provider時才能創(chuàng)建或者調(diào)用它。語法類似:
  1. <provider android:name="com.easymorse.cp.MyContentProvider"
  2.             android:authorities="com.easymorse.cp.mycp"></provider>
復(fù)制代碼

android:name要寫ContentProvider繼承類的全名。android:authorities要寫和CONTENT_URI常量的B部分(見上面圖)。注意不要把上圖C和D部分加到authorities中去。authorities是用來識別ContentProvider的,C和D部分實際上是ContentProvider內(nèi)部使用的。


作為ANDROIDL四大組件(Compenent:Activity, Service, BreadcaseReceiver,
ContentProvider)之一的Content provider,為其它應(yīng)用程序(也可以是提供該
Content provider的應(yīng)用程序)提供了一個接口一致數(shù)據(jù)儲存模型。通過該接口,你可以
方便地提取你想要的數(shù)據(jù),修改或者是刪除都會變得相當(dāng)方便。依照ANDROI組件模型的原理,
把數(shù)據(jù)儲存與數(shù)據(jù)顯示分離天來,這不但提高了組件重用性,也同時提供更高的完全性(每一
個Content Provider都有自己的許可屬性)。作為數(shù)據(jù)儲存的后端,你可以使用有Sqlite3
保存數(shù)據(jù),也可以使用文件系統(tǒng)保存,甚至是使用網(wǎng)絡(luò);后端的多樣性給得程序的設(shè)計更富有
彈性。
    今天結(jié)合自己開發(fā)的經(jīng)驗,總結(jié)一下實現(xiàn)Content Provider的幾點(diǎn)經(jīng)驗,不足之處,歡迎
討論(bangbang.song@gmail.com)


每一個實現(xiàn)都在從ContentProvider類繼承,并實現(xiàn)ContentProvider的抽象函數(shù):
delete(), insert(), query(), update(), getType()和onCreate().

代碼片斷:
  1. class myContentProvider extends ContentProvider {
  2.         //刪除符合指定條件的記錄
  3.         public int delete(Uri uri, String selection, String[] selectionArgs);
  4.         //插入一個新的記錄
  5.         public Uri insert(Uri uri, ContentValues values);
  6.         // 查詢符合指定條件的記錄
  7.         public Cursor query(Uri uri, String[] projecttion, String selection, String[] selectionArgs, String sortOrder);
  8.         //更新條例指定條件的記錄
  9.         public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
  10.         //基于給定uri,返回該uri表示的類型
  11.         public String getType(Uri uri);
  12.         //創(chuàng)建數(shù)據(jù)儲存后端,如數(shù)據(jù)庫,文件,網(wǎng)絡(luò)接口等
  13.         public boolean onCreate();

  14.         ......
復(fù)制代碼
如果使用Sqlite3作為數(shù)據(jù)后端(本例只討論這種情況,如使用其它方法,如文件系統(tǒng),網(wǎng)絡(luò),則大同小異),數(shù)據(jù)庫的創(chuàng)建,
打開,更新,可以使用幫助類SQLiteHelper來完成,該類將對數(shù)據(jù)庫的操作作了有效的封裝,有利于我們使用。
代碼片斷:
  1. class youtDbHelper extends SQLiteHelper {
  2.     // 創(chuàng)建數(shù)據(jù)庫
  3.     public void onCreate(SQLiteDatabase db);
  4.     // 更新數(shù)據(jù)庫
  5.     public void onUpdate(SQLiteDatabase db, int oldVersion, int newVersion)
  6.    
  7.     ......
  8. }
復(fù)制代碼
為方便其它應(yīng)用程序與該ContentProvider通信,通常我們要提供一個公共的Uri: CONTENT_URI,其它組件正是通過這一Uri,
與ContentProvider交流。在我們的ContentProvider創(chuàng)建好之后,我們不直接與之打交道,而是通過ANDROID的
ContentResolver進(jìn)行操作。通過ANDROID系統(tǒng)的自動分析,會選擇一個合適的ContentProvider進(jìn)行通信。只要我們指定
我們之前定義的CONTENT_URI,就可能與之勾通了。
代碼片斷:
  1.         Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);         
  2.     //或者
  3.     Cursor cursor = manageQuery(uri, null, null, null, null);
  4.     // 可以使用游標(biāo)cursor獲取想要的信息
  5.     ...
  6.     // 刪除
  7.     int count = getContentResolver().delete(Uri url, String where, String[] selectionArgs);
  8.    ......
復(fù)制代碼

對Uri的說明:
   Uri(unified Resource identifier)就是統(tǒng)一資源標(biāo)識,指定了一個特定的資源,遵照RFC2396規(guī)范。
   一般格式為:
     <scheme>://<authority><path><query>#<fragment>
  例如: content://your.contentprovider/what_u_provided
    其中scheme=content 表示專為ContentProvider使用。
 
補(bǔ)充如下:
android有一個獨(dú)特之處就是,數(shù)據(jù)庫只能被它的創(chuàng)建者所使用,其他的應(yīng)用是不能訪問到的,所以如果你想實現(xiàn)不同應(yīng)用之間的數(shù)據(jù)共享,就不得不用content
provider了。
在Android中,content
provider是一個特殊的存儲數(shù)據(jù)的類型,它提供了一套標(biāo)準(zhǔn)的接口用來獲取以及操作數(shù)據(jù)。并且,android自身也提供了幾個現(xiàn)成的content
provider:Contacts,
Browser, CallLog, Settings, MediaStore.

應(yīng)用可以通過一個唯一的ContentResolver
interface來使用具體的某個content
provider。

ContentResolver
cr = getContentResolver();
然后你就可以用ContentResolver提供的方法來使用你需要的content provider了。其中contentResolver提供的方法包括query(),insert(),update()等。要使用這些方法,還會涉及到一個東西,那就是Uri。你可以將它理解成一個string形式的contentProvider的完全路徑,它的形式為:////,
例如:
content://browser/bookmarks
content://contacts/people
content://contacts/people/3
下面結(jié)合一個實例來看我們?nèi)绾问褂靡粋€已有的content provider,給例子展示了如何從已有的電話本中讀出聯(lián)系人信息:
               
               
                package com.android.cp;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.util.Log;
import android.widget.Toast;
public class ContentProviderTest extends Activity {
    private final String TAG = "ContentProviderTest";
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG,"enter onCreate");
        setContentView(R.layout.main);
        createCP();
    }
   
    public void createCP()
    {
        ContentResolver cr = getContentResolver();
        
        //Cursor cur = managedQuery(People.CONTENT_URI, null, null, null, null);
        Cursor cur = cr.query(People.CONTENT_URI, null, null, null, null);
        
        getColumnData(cur);
    }
   
    private void getColumnData(Cursor cur){
        if (cur.moveToFirst()) {
            String name;
            String phoneNumber;
            int nameColumn = cur.getColumnIndex(People.NAME);
            int phoneColumn = cur.getColumnIndex(People.NUMBER);
        
            do {
                // Get the field values
                name = cur.getString(nameColumn);
                phoneNumber = cur.getString(phoneColumn);
               
                Log.i(TAG, "name="+name);
                DisplayToast(name+"  "+phoneNumber);
            } while (cur.moveToNext());
        }
    }
   
    public void DisplayToast(String s)
    {
    Toast.makeText(this,
    s,
    Toast.LENGTH_LONG).show();
    }
}
               
               
               
               
需要注意的是,你需要在你的Manifest文件中加上
               
                uses-permission
       android:name="android.permission.READ_CONTACTS">
/uses-permission>
否則,程序無法成功運(yùn)行。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android 開發(fā)中使用 SQLite 數(shù)據(jù)庫
Android多媒體分析(二)MediaStore
android中跨進(jìn)程通訊的4種方式
Informix 數(shù)據(jù)庫函數(shù)庫及其用法
ListView的Adapter使用 之 初學(xué)ArrayAdapter<String>
ruby操作常用數(shù)據(jù)庫
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服