Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ContentProvider

ContentProvider

編輯:關於Android編程

API Introduction
Content providers are one of the primary building blocks(構件) of Android applications, providing content to applications. They encapsulate (封裝)data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple (多個)applications. For example, the contacts data is used by multiple applications and must be stored in a content provider. If you don’t need to share data amongst multiple applications you can use a database directly via (通過)SQLiteDatabase.

When a request is made via a ContentResolver the system inspects the authority of the given URI and passes the request to the content provider registered with the authority. The content provider can interpret the rest of the URI however it wants. The UriMatcher class is helpful for parsing URIs.(通過UriMatcher 解析URI)

當我們需要創建應用程序的ContentProvider時就會需要用到UriMatcher


在創建內容提供者之前,先了解怎麼連接到內容提供者,並讀取數據.

ContentResolver的基本用法(讀取內容)

對於每一個應用程序來說,如果想要訪問內容提供器中共享的數據,就一定要借助ContentResolve類,可以通過Context中的getContentResolver()方法獲取到該類的實例。ContentResolver中提供了一系列的方法用於對數據進行CRUD操作,其中insert()方法用於添加數據,update()方法用於更新數據,delete()方法用於刪除數據,query()方法用於查詢數據。有沒有似曾相識的感覺?沒錯,SQLiteDatabase中也是使用的這幾個方法來進行CRUD操作的,只不過它們在方法參數上稍微有一些區別。
  
  不同於SQLiteDatabase,ContentResolver中的增刪改查方法都是不接收表名參數的,而是使用一個Uri參數代替,這個參數被稱為內容URI。內容URI給內容提供器中的數據建立了唯一標識符,它主要由兩部分組成,權限(authority)和路徑(path)。權限是用於對不同的應用程序做區分的,一般為了避免沖突,都會采用程序包名的方式來進行命名。比如某個程序的包名是com.example.app,那麼該程序對應的權限就可以命名為com.example.app. provider。路徑則是用於對同一應用程序中不同的表做區分的,通常都會添加到權限的後面。比如某個程序的數據庫裡存在兩張表,table1和table2,這時就可以將路徑分別命名為/table1和/table2,然後把權限和路徑進行組合,內容URI就變成了com.example.app.provider/table1和com.example.app.provider/table2。不過,目前還很難辨認出這兩個字符串就是兩個內容URI,我們還需要在字符串的頭部加上協議聲明。因此,內容URI最標准的格式寫法如下:

content://com.example.app.provider/table1
content://com.example.app.provider/table2

有沒有發現,內容URI可以非常清楚地表達出我們想要訪問哪個程序中哪張表裡的數據。也正是因此,ContentResolver中的增刪改查方法才都接收Uri對象作為參數,因為使用表名的話系統將無法得知我們期望訪問的是哪個應用程序裡的表。
在得到了內容URI字符串之後,我們還需要將它解析成Uri對象才可以作為參數傳入。解析的方法也相當簡單,代碼如下所示:

Uri uri = Uri.parse("content://com.example.app.provider/table1")

現在我們就可以使用這個Uri對象來查詢table1表中的數據了

public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
uri — [ from table_name ] ———指定查詢某個應用程序下的某一張表 projection —[ select column1, column2 ]——-指定查詢的列名 selection —[where column = value] —–指定where的約束條件 selectionArgs ——–為where中的占位符提供具體的值 orderBy —[select column1, column2]———指定查詢結果的排序方式

查詢完成後返回的仍然是一個Cursor對象,這時我們就可以將數據從Cursor對象中逐個讀取出來了。讀取的思路仍然是通過移動游標的位置來遍歷Cursor的所有行,然後再取出每一行中相應列的數據,代碼如下所示:

if (cursor != null) {
    while (cursor.moveToNext()) {
        String column1 = cursor.getString(cursor.getColumnIndex("column1"));
        int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
    }
    cursor.close();
}

掌握了最難的查詢操作,剩下的增加、修改、刪除操作就更不在話下了。我們先來看看如何向table1表中添加一條數據,代碼如下所示:

ContentValues values = new ContentValues();
values.put("column1", "text");
values.put("column2", 1);
getContentResolver().insert(uri, values)

ContentResolver的update()方法實現,代碼如下所示:

ContentValues values = new ContentValues();
values.put("column1", "");
getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[] {"text", "1"});

可以調用ContentResolver的delete()方法將這條數據刪除掉,代碼如下所示:

getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

讀取聯系人

手機的聯系人默認是內容提供者保存數據,你只需要知道URI就可以讀取裡面的內容
讀取模擬器上的聯系人,當然你要添加幾個聯系人


MainActivity.java

public class MainActivity extends Activity {

    ListView contactsView;

    ArrayAdapter adapter;

    List contactsList = new ArrayList();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        contactsView = (ListView) findViewById(R.id.contacts_view);
        adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList);
        contactsView.setAdapter(adapter);
        readContacts();
    }

    private void readContacts() {
        Cursor cursor = null;
        try {
            // 查詢聯系人數據 URI=ContactsContract.CommonDataKinds.Phone.CONTENT_URI
            cursor = getContentResolver().query(
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    null, null, null, null);
            while (cursor.moveToNext()) {
                // 獲取聯系人姓名
                String displayName = cursor.getString(cursor.getColumnIndex(
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                // 獲取聯系人手機號
                String number = cursor.getString(cursor.getColumnIndex(
                        ContactsContract.CommonDataKinds.Phone.NUMBER));
                contactsList.add(displayName + "\n" + number);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

}

布局


    

讀取聯系人權限

結果
通過ListView顯示內容,在真實手機上一樣可以運行
這裡寫圖片描述

創建內容提供者

目錄結構
這裡寫圖片描述

代碼比較多,頁面底部有源碼">源碼下載

建議通過源碼代碼學習

databasetest


DatabaseProvider .java

public class DatabaseProvider extends ContentProvider {

    public static final int BOOK_DIR = 0;

    public static final int BOOK_ITEM = 1;

    public static final int CATEGORY_DIR = 2;

    public static final int CATEGORY_ITEM = 3;

    public static final String AUTHORITY = "com.peng.databasetest.provider";

    private static UriMatcher uriMatcher;

    private MyDatabaseHelper dbHelper;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
        uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
        uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
        uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
    }

    @Override
    public boolean onCreate() {
        dbHelper = new MyDatabaseHelper(getContext(),"BookStore.db", null, 2);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = null;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null,
                    sortOrder);
            break;
        case CATEGORY_DIR:
            cursor = db.query("Category", projection, selection, selectionArgs, null, null,
                    sortOrder);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null,
                    null, sortOrder);
            break;
        default:
            break;
        }
        return cursor;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Uri uriReturn = null;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
        case BOOK_ITEM:
            long newBookId = db.insert("Book", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
            break;
        case CATEGORY_DIR:
        case CATEGORY_ITEM:
            long newCategoryId = db.insert("Category", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
            break;
        default:
            break;
        }
        return uriReturn;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int updatedRows = 0;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            updatedRows = db.update("Book", values, selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            updatedRows = db.update("Book", values, "id = ?", new String[] { bookId });
            break;
        case CATEGORY_DIR:
            updatedRows = db.update("Category", values, selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId });
            break;
        default:
            break;
        }
        return updatedRows;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int deletedRows = 0;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            deletedRows = db.delete("Book", selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
            break;
        case CATEGORY_DIR:
            deletedRows = db.delete("Category", selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            deletedRows = db.delete("Category", "id = ?", new String[] { categoryId });
            break;
        default:
            break;
        }
        return deletedRows;
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            return "vnd.android.cursor.dir/vnd.com.peng.databasetest.provider.book";
        case BOOK_ITEM:
            return "vnd.android.cursor.item/vnd.com.peng.databasetest.provider.book";
        case CATEGORY_DIR:
            return "vnd.android.cursor.dir/vnd.com.peng.databasetest.provider.category";
        case CATEGORY_ITEM:
            return "vnd.android.cursor.item/vnd.com.peng.databasetest.provider.category";
        }
        return null;
    }

}

MainActivity .java

public class MainActivity extends Activity {

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
            }
        });

        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("name", "The Da Vinci Code");
                values.put("author", "Dan Brown");
                values.put("pages", 454);
                values.put("price", 16.96);
                db.insert("Book", null, values);
                values.clear();
                values.put("name", "The Lost Symbol");
                values.put("author", "Dan Brown");
                values.put("pages", 510);
                values.put("price", 19.95);
                db.insert("Book", null, values);
            }
        });

        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price", 10.99);
                db.update("Book", values, "name = ?",
                        new String[]{"The Da Vinci Code"});
            }
        });

        Button deleteButton = (Button) findViewById(R.id.delete_data);
        deleteButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book", "pages > ?", new String[]{"500"});
            }
        });

        Button queryButton = (Button) findViewById(R.id.query_data);
        queryButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri
                        .parse("content://com.peng.databasetest.provider/book");
                Cursor cursor = getContentResolver().query(uri, null, null,
                        null, null);
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String name = cursor.getString(cursor
                                .getColumnIndex("name"));
                        String author = cursor.getString(cursor
                                .getColumnIndex("author"));
                        int pages = cursor.getInt(cursor
                                .getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor
                                .getColumnIndex("price"));
                        Log.d("MainActivity", "book name is " + name);
                        Log.d("MainActivity", "book author is " + author);
                        Log.d("MainActivity", "book pages is " + pages);
                        Log.d("MainActivity", "book price is " + price);
                    }
                    cursor.close();
                }
            }
        });

        Button replaceData = (Button) findViewById(R.id.replace_data);
        replaceData.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.beginTransaction();
                try {
                    db.delete("Book", null, null);
                    // if (true) {
                    // throw new NullPointerException();
                    // }
                    ContentValues values = new ContentValues();
                    values.put("name", "Game of Thrones");
                    values.put("author", "George Martin");
                    values.put("pages", 720);
                    values.put("price", 20.85);
                    db.insert("Book", null, values);
                    db.setTransactionSuccessful();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    db.endTransaction();
                }
            }
        });
    }

}

MyDatabaseHelper .java

public class MyDatabaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK = "create table Book ("
            + "id integer primary key autoincrement, " 
            + "author text, "
            + "price real, " 
            + "pages integer, " 
            + "name text)";

    public static final String CREATE_CATEGORY = "create table Category ("
            + "id integer primary key autoincrement, "
            + "category_name text, "
            + "category_code integer)";

    public MyDatabaseHelper(Context context, String name,
            CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }

}

清單文件


        

這個屬性很重要android:exported
這個屬性用於指示該服務是否能被其他程序應用組件調用或跟他交互; 取值為(true | false),如果設置成true,則能夠被調用或交互,否則不能;設置為false時,只有同一個應用程序的組件或帶有相同用戶ID的應用程序才能啟動或綁定該服務。


布局文件

訪問上面內容提供者的數據

providertest


MainActivity .java

public class MainActivity extends Activity {

    private String newId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri
                        .parse("content://com.peng.databasetest.provider/book");
                ContentValues values = new ContentValues();
                values.put("name", "A Clash of Kings");
                values.put("author", "George Martin");
                values.put("pages", 1040);
                values.put("price", 55.55);
                Uri newUri = getContentResolver().insert(uri, values);
                newId = newUri.getPathSegments().get(1);
            }
        });
        Button queryData = (Button) findViewById(R.id.query_data);
        queryData.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri
                        .parse("content://com.peng.databasetest.provider/book");
                Cursor cursor = getContentResolver().query(uri, null, null,
                        null, null);
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String name = cursor.getString(cursor
                                .getColumnIndex("name"));
                        String author = cursor.getString(cursor
                                .getColumnIndex("author"));
                        int pages = cursor.getInt(cursor
                                .getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor
                                .getColumnIndex("price"));
                        Log.d("MainActivity", "book name is " + name);
                        Log.d("MainActivity", "book author is " + author);
                        Log.d("MainActivity", "book pages is " + pages);
                        Log.d("MainActivity", "book price is " + price);
                    }
                    cursor.close();
                }
            }
        });
        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri
                        .parse("content://com.peng.databasetest.provider/book/" + newId);
                ContentValues values = new ContentValues();
                values.put("name", "A Storm of Swords");
                values.put("pages", 1216);
                values.put("price", 24.05);
                getContentResolver().update(uri, values, null, null);
            }
        });
        Button deleteData = (Button) findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri
                        .parse("content://com.peng.databasetest.provider/book/" + newId);
                getContentResolver().delete(uri, null, null);
            }
        });
    }

}

源碼

創建內容提供者databasetest
讀取內容提供者providertest
讀取聯系人源碼

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved