(轉)ContentProvider 內容提供者

來源:互聯網
上載者:User

標籤:

1.1.  什麼是內容提供者

  內容提供者是Android中的四大組件之一,可以將應用中的資料對外進行共用

  內容提供者將資料的訪問方式統一,不必針對不同資料類型採取不同的存取原則

  內容提供者將資料封裝,只暴露出我們希望提供給其他程式的資料

  內容提供者中資料更改可被監聽

 

1.2.  建立內容提供者

   定義類繼承ContentProvider,根據需要重寫內部方法

     在資訊清單檔的<application>節點下進行配置,<provider>標籤中需要指定name和authorities屬性

    name為類名,包名從程式Package開始,以“.”開始

    authorities:是訪問Provider時的路徑,要唯一

     URI代表要操作的資料,由scheme、authorites、path三部分組成

    content://cn.itcast.provider.itcast/person

    scheme:固定為content,代表訪問內容提供者

    authorites:<provider>節點中的authorites屬性

    path:程式定義的路徑,可根據商務邏輯定義

 

1.3.  完成CRUD方法

Ÿ   當程式調用CRUD方法時會傳入Uri

Ÿ   我們通過Uri判斷調用者要操作的資料

可以使用工具類UriMatcher來判斷Uri

addURI方法可以添加Uri

match方法可以匹配一個Uri判斷其類型

Ÿ   根據商務邏輯操作資料

 

1.4.  完成getType方法

Ÿ   如果返回資料是單條資料:vnd.android.cursor.item

Ÿ   如果返回資料是多條資料:vnd.android.cursor.dir

public class PersonProvider extends android.content.ContentProvider {    private static final int PERSON = 0;    private static final int PERSON_ID = 1;    private UriMatcher matcher;    private DBOpenHelper helper;    @Override    public boolean onCreate() {        matcher = new UriMatcher(UriMatcher.NO_MATCH);        matcher.addURI("com.demo.sqlite.provider", "person", PERSON); // 添加一個可以匹配的Uri        matcher.addURI("com.demo.sqlite.provider", "person/#", PERSON_ID);        helper = new DBOpenHelper(getContext());        return true;    }    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        switch (matcher.match(uri)) { // 對Uri進行匹配        case PERSON_ID:            String idSelection = "id = " + ContentUris.parseId(uri);    //  Converts the last path segment to a long.            // 注意此處字串拼裝            selection = selection == null ? idSelection : idSelection + " AND " + selection;        case PERSON:            SQLiteDatabase db = helper.getReadableDatabase();            return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);        default:            throw new IllegalArgumentException("No Match Uri " + uri);        }    }    @Override    public Uri insert(Uri uri, ContentValues values) {        switch (matcher.match(uri)) {        case PERSON:            SQLiteDatabase db = helper.getWritableDatabase();            long id = db.insert("person", null, values);        // 使用 db.insert() 方法插入資料,返回 id                                                                                    // 而 db.exceSQL(sql)方式插入資料,返回 void            // return     Uri.parse("content://com.demo.sqlite.provider/person/" + id);        // 與下句效果相同            return ContentUris.withAppendedId(uri, id);        // Appends the given ID to the end of the path.            default:                throw new IllegalArgumentException("No Match Uri " + uri);        }    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        switch (matcher.match(uri)) {        case PERSON_ID:            long id = ContentUris.parseId(uri);            selection = selection == null ? "id = " + id : "id = " +id + " AND " +selection;        case PERSON:            SQLiteDatabase db = helper.getWritableDatabase();            // return : The number of rows affected            return db.delete("person", selection, selectionArgs);         default:            throw new IllegalArgumentException("No Match Uri " + uri);        }    }    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        switch (matcher.match(uri)) {        case PERSON_ID:            long id = ContentUris.parseId(uri);            selection = selection == null ? "id = " + id : "id = " + id + " AND " + selection;        case PERSON:            SQLiteDatabase db = helper.getWritableDatabase();            // @return the number of rows affected            return db.update("person", values, selection, selectionArgs);        default:            throw new IllegalArgumentException("No Match Uri " + uri);        }    }        @Override    public String getType(Uri uri) {        switch (matcher.match(uri)) {        case PERSON_ID:            return "vnd.android.cursor.item/person";        case PERSON:            return "vnd.android.cursor.dir/person";         default:            throw new IllegalArgumentException("No Match Uri " + uri);        }    }

 

1.5.  訪問內容提供者

Ÿ   通過Context獲得ContentResolver對象

Ÿ   調用ContentResolver對象的方法即可訪問內容提供者

 

    private static final String TAG = "ProviderTest";    // 查詢 id = 36    public void testQuery1() {        // 通過 ContentResolver 調用 ContentProvider 提供的方法        ContentResolver resolver = getContext().getContentResolver();        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");        Cursor c = resolver.query(uri, new String[] { "id", "name", "balance" }, "id = ?", new String[] { "36" }, null);        if (c.moveToNext()) {            Person person = new Person(c.getInt(0), c.getString(1), c.getInt(2));            Logger.i(TAG, person.toString());        }    }    // 查詢所有 person    public void testQuery2() {        // 通過 ContentResolver 調用 ContentProvider 提供的方法        ContentResolver resolver = getContext().getContentResolver();        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");        Cursor c = resolver.query(uri, null, null, null, null);        while (c.moveToNext()) {            Person person = new Person(c.getInt(0), c.getString(1), c.getInt(2));            Logger.i(TAG, person.toString());        }    }    // 通過附帶 id 查詢 person    public void testQuery3() {        // 通過 ContentResolver 調用 ContentProvider 提供的方法        ContentResolver resolver = getContext().getContentResolver();        // Uri        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/55");        Cursor c = resolver.query(uri, null, "name = ?", new String[] { "Ashia_54" }, null);        while (c.moveToNext()) {            Person person = new Person(c.getInt(0), c.getString(1), c.getInt(2));            Logger.i(TAG, person.toString());        }    }    public void testInsert() {        ContentResolver resolver = getContext().getContentResolver();        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");        ContentValues values = new ContentValues();        Person person = new Person("another Person uri insert", 7000);        values.put("name", person.getName());        values.put("balance", person.getBalance());        Uri reUri = resolver.insert(uri, values);        Cursor c = resolver.query(reUri, null, null, null, null);        if (c.moveToNext()) {            Person rePerson = new Person(c.getInt(0), c.getString(1), c.getInt(2));            Logger.i(TAG, rePerson.toString());        }    }        public void testDelete() {        // ContentResolver :This class provides applications access to the content model.        ContentResolver resolver = getContext().getContentResolver();                Uri url = Uri.parse("content://com.demo.sqlite.provider/person/121");        // 忘記加 = ?, 異常如下        // android.database.sqlite.SQLiteException: bind or column index out of range         long id = resolver.delete(url, "name = ?", new String[] {"zhangsan"});         Logger.i(TAG, id + "");                  id = resolver.delete(url, null, null);         Logger.i(TAG, id + "");    }        public void testDeleteAll() {        ContentResolver resolver = getContext().getContentResolver();        Uri url = Uri.parse("content://com.demo.sqlite.provider/person");        int deleteNum = resolver.delete(url, null, null);        Logger.i(TAG, deleteNum + "");    }        public void testUpdate() {        ContentResolver resolver = getContext().getContentResolver();        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/122");        ContentValues values = new ContentValues();        values.put("balance", 8000);        int update = resolver.update(uri, values, "balance = ?", new String[] {"9000"});        Logger.i(TAG, update + "");    }        public void testUpdateById() {        ContentResolver resolver = getContext().getContentResolver();        ContentValues values = new ContentValues();        values.put("name", "new name");        values.put("balance", 7000);        values.put("id", 2);        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/123");        int update = resolver.update(uri, values, null, null);        Logger.i(TAG, update + "");    }    // Uri寫錯,異常    // java.lang.IllegalArgumentException: Unknown URI         // 主鍵 id 重複,異常    // android.database.sqlite.SQLiteConstraintException        public void testGetType() {        ContentResolver resolver = getContext().getContentResolver();        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/1");        Logger.i(TAG, resolver.getType(uri));        uri = Uri.parse("content://com.demo.sqlite.provider/person");        Logger.i(TAG, resolver.getType(uri));    }

 

1.6.  監聽內容提供者資料變化

Ÿ   在內容提供者中可以通知其他程式資料發生變化

通過Context的getContentResolver()方法擷取ContentResolver

調用其notifyChange()方法發送資料修改通知

Ÿ   在其他程式中可以通過ContentObserver監聽資料變化

通過Context的getContentResolver()方法擷取ContentResolver

調用其registerContentObserver()方法指定對某個Uri註冊ContentObserver

自訂ContentObserver,重寫onChange()方法擷取資料

 

發送資料修改通知

    public Uri insert(Uri uri, ContentValues values) {        switch (matcher.match(uri)) {        case PERSON:            SQLiteDatabase db = helper.getWritableDatabase();            long id = db.insert("person", null, values);              // Notify registered observers that a row was updated. 註冊 observer            // @param observer The observer that originated the change, may be null            // 產生改變的Observer. 此處為Provider帶來的改變,傳 null            this.getContext().getContentResolver().notifyChange(uri, null);     // 發送修改通知                        // return     Uri.parse("content://com.demo.sqlite.provider/person/" + id);             return ContentUris.withAppendedId(uri, id);             default:                throw new IllegalArgumentException("No Match Uri " + uri);        }    }

 

定義一個ContentObserver,監聽Uri所對應的內容提供者的變化

    protected static final String TAG = "ObserverActivity";    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        // 定義一個ContentObserver        ContentObserver observer = new ContentObserver(new Handler()) {            /**             * Returns true if this observer is interested in notifications for             * changes made through the cursor the observer is registered with.             */            // 是否傳遞自己的改變            @Override            public boolean deliverSelfNotifications() {                return super.deliverSelfNotifications();            }            /**             * This method is called when a change occurs to the cursor that is             * being observed.             *              * @param selfChange             *            true if the update was caused by a call to commit on             *            the cursor that is being observed.             */            // 當被監聽的內容發生了改變時,調用該方法            @Override            public void onChange(boolean selfChange) {                Logger.i(TAG, "監聽到了變化");                // 列印出最後插入的資訊                ContentResolver resolver = getContentResolver();                Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");                // SELECT * FROM person ORDER BY id DESC LIMIT 1;                Cursor c = resolver.query(uri, null, null, null, "id DESC LIMIT 1");                if(c.moveToNext()) {                    String result = "id = " + c.getInt(0) + ", name = " + c.getString(1) + ", balance = " + c.getInt(2);                    Logger.i(TAG, result);                    Toast.makeText(ObserverActivity.this, result, 1).show();                }                // 父類未做任何實現                super.onChange(selfChange);            }        };                Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");        // 註冊一個ContentObserver        /*         * @param notifyForDescendents          * If true changes to URIs beginning with uri will also cause notifications to be sent.          * Iffalse only changes to the exact URI specified by uri will cause notifications to be sent.          * If true, than any URI values  at or below the specified URI will also trigger a match.         */        // 是否監聽以 "uri" 開頭 的其他 uri        getContentResolver().registerContentObserver(uri, true, observer);    }

 

通過ContentObserver,監測內容改變,自動更新ListView

        bt_insert = (Button) findViewById(R.id.bt_insert);        bt_insert.setOnClickListener(new OnClickListener() {            public void onClick(View v) {                ContentResolver resolver = ListViewSimpleCursorAdapterActivity.this.getContentResolver();                Uri url = Uri.parse("content://com.demo.sqlite.provider/person");                ContentValues values = new ContentValues();                values.put("name", "test name");                values.put("balance", 3000);                resolver.insert(url, values);            }        });        lv_person.setOnItemClickListener(new MyOnItemClickListener());        Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");        getContentResolver().registerContentObserver(uri, false, new MyContentObserver(new Handler()));    public class MyContentObserver extends ContentObserver {        public MyContentObserver(Handler handler) {            super(handler);        }        @Override        public void onChange(boolean selfChange) {            // 當所監聽的內容發生了改變,則更新lv中的資料            Cursor c = new PersonDAO(ListViewSimpleCursorAdapterActivity.this).queryAllCursor();            SimpleCursorAdapter adapter = new SimpleCursorAdapter(ListViewSimpleCursorAdapterActivity.this, //                    R.layout.listview_item, //                    c, //                    new String[] { "_id", "name", "balance" }, //                    new int[] { R.id.tv_id, R.id.tv_name, R.id.tv_balance });            lv_person.setAdapter(adapter);            lv_person.setOnItemClickListener(new MyOnItemClickListener());            super.onChange(selfChange);            Logger.i(TAG, "onChange");        }    }

 

錯誤

  Uri寫錯,異常  java.lang.IllegalArgumentException: Unknown URI 
  主鍵 id 重複,異常  android.database.sqlite.SQLiteConstraintException

 

測試ListView更新時,介面總是自動關閉

如果自己是內容提供者,也是內容觀察者,

在測試案例中更改內容,應用會強制退出

(轉)ContentProvider 內容提供者

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.