ContentProvider:內容提供者
1、爲存儲和讀取數據提供了統一的接口
2、使用ContentProvider,應用程序可以實現數據共享
3、android內置的許多數據都是使用ContentProvider形式,供開發者調用的(如視頻,音頻,圖片,通訊錄等)
4、當應用繼承ContentProvider類,並重寫該類用於提供數據和存儲數據的方法,就可以向其他應用共享其數據。
先來了解一下Uri:
Uri,即通用資源標識符
1、Uri代表要操作的數據,Android上可用的每種資源 - 圖像、視頻片段等都可以用Uri來表示
2、Uri一般由三部分組成:訪問資源的命名機制;存放資源的主機名; 資源自身的名稱,由路徑表示。
Android的Uri由以下三部分組成: "content://"+數據的路徑+標示ID(可選)、
如:所有聯繫人的Uri: content://contacts/people
某個聯繫人的Uri: content://contacts/people/5 //聯繫人中id爲5的聯繫人
3、如果要把一個字符串轉換成Uri,可以使用Uri類中的parse()方法,如下:
Uri uri = Uri.parse("content://com.archer.ContentProvider")
ContentResolver:
在android中,每個應用程序是可以實現數據共享的,對於每一個應用程序程序都擁有一個ContentProvider實例進行存儲,
而ContentResolver則是用於管理所有程序的ContentProvider實例,通過ContentRescolver可以對數據進行添加、刪除、修改和查詢操作
通過getContentRescolver()獲取實例
下面通過創建一個Content Provider,並使用 SQLLite數據庫實現數據共享
首先,定義ContentProvider的CONTENT_URI,並且是public static final的Uri類型的類變量
必須爲其制定一個唯一的字符串值,一般用類的全名稱命名
package com.ContentProviderDemo.Archer; import android.net.Uri; import android.provider.BaseColumns; public class MyUsers { public static final String AUTHORITY = "com.archer.ContentProvider"; //BaseColumn類中已經包含了 _id 字段 public static final class User implements BaseColumns{ public static final Uri CONTENT_URI = Uri.parse("content://com.archer.ContentProvider"); //表數據列 public static final String USER_NAME = "USER_NAME"; } }
之後創建一個類繼承ContentProvider
package com.ContentProviderDemo.Archer; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; public class MyContentProvider extends ContentProvider{ /** * 定義一個SQLiteDatabase變量 * Android提供了一個名爲SQLiteDatabase的類,它封裝了一些操作數據庫的API。 * 使用它能實現基本的CRUD(插入、查詢、更新、刪除)操作,通過getWritableDatabase()和getReadableDatabase()可以獲取數據庫實例 */ private SQLiteDatabase sqlDB; private DatabaseHelper dbHelper; private static final String DATABASE_NAME = "Users.db"; //數據庫名 private static final int DATABASE_VERSION = 1; //數據庫版本 //表名 private static final String TABLE_NAME = "User";//表名 /** * 首先需要創建數據庫(定義一個內部類,繼承SQLiteOpenHelper類,重寫其方法) * SQliteOpenHelper是一個抽象類,來管理數據庫的創建和版本的管理。 * 要使用它必須實現它的onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase, int, int)方法 * onCreate:當數據庫第一次被建立的時候被執行,例如創建表,初始化數據等。 * onUpgrade:當數據庫需要被更新的時候執行,例如刪除舊錶,創建新表。 * @author Administrator */ private static class DatabaseHelper extends SQLiteOpenHelper{ /** * 創建數據庫的構造方法 * name 數據庫的名字 * factory 查詢數據庫的遊標工廠一般情況下用sdk默認的 * version 數據庫的版本一般大於0 */ public DatabaseHelper(Context context){ super(context,DATABASE_NAME,null,DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String sq1 = "Create table " + TABLE_NAME + "( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);"; //創建表的sql語句 db.execSQL(sq1); //創建表 } /** * 更新數據的時候調用的方法,如新增表、修改數據 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //增加一列 db.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME); onCreate(db); } } @Override public int delete(Uri uri, String s, String[] arg2) { return 0; } @Override public String getType(Uri arg0) { return null; } /** * 插入數據 * ContentValues類負責存儲一些名值對,的名是一個String類型,而值都是基本類型。 */ @Override public Uri insert(Uri uri, ContentValues contentValues) { //以讀寫方式打開數據庫,一旦數據庫的磁盤空間滿了,數據庫就只能讀而不能寫,就會打開失敗 sqlDB = dbHelper.getWritableDatabase(); //插入一條新的紀錄,如果插入成功則會返回這條記錄的id,如果插入失敗會返回-1 long rowId = sqlDB.insert(TABLE_NAME, "", contentValues); if(rowId > 0){ // ContentUris 類用於獲取Uri路徑後面的ID部分 //appendId:爲該Uri加上ID Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build(); // getContextResolver().notifyChange():獲得一個ContextResolver對象並且更新裏面的內容。 getContext().getContentResolver().notifyChange(rowUri, null); return rowUri; } throw new SQLException("Fail to insert row into"+uri); } /** * 這是一個回調函數,當生成所在類的對象時,這個方法被調用,創建一個數據庫 */ @Override public boolean onCreate() { dbHelper = new DatabaseHelper(getContext()); return (dbHelper == null) ? false:true; } /** * 查詢 */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { //SQLiteQueryBuilder 是一個構造SQL查詢語句的輔助類。 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); //getReadableDatabase():先以讀寫方式打開數據庫,如果數據庫的磁盤空間滿了,就會打開失敗,當打開失敗後會繼續嘗試以只讀方式打開數據庫 SQLiteDatabase db = dbHelper.getReadableDatabase(); qb.setTables(TABLE_NAME); /** * Cursor 是每行的集合 * 在Android中 查詢數據是通過Cursor 類來實現的。當我們使用 SQLiteDatabase.query()方法時,就會得到Cursor對象, * Cursor所指向的就是每一條數據 */ Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Override public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { return 0; } }
在AndroidManifest.xml中進行註冊:
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name=".MyContentProvider" android:authorities="com.archer.ContentProvider"> </provider> <!-- android:authorities屬性配置的就是該ContentProvider的名字,是它在Android系統中的名字,我們是通過這個名字去找對應的ContentProvider對象的--> </application>
最後,創建一個新的工程(測試用)
package com.ContentProviderDemo.Archer; import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; /** * 在另一個工程中訪問創建的數據庫,不用再註冊provider,否則會保存 * @author Administrator * */ public class MainActivity extends Activity { public static final String AUTHORITY = "com.archer.ContentProvider"; private Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); insertRecord("record1"); displayRecords(); } //插入數據 private void insertRecord(String userName) { ContentValues values = new ContentValues(); values.put("USER_NAME", userName); getContentResolver().insert(CONTENT_URI, values); } //查詢數據 private void displayRecords() { // 該數組中包含了所有要返回的字段 String columns[] = new String[] { "_id", "USER_NAME" }; Uri myUri = CONTENT_URI; Cursor cur = getContentResolver().query(myUri, columns, null, null,null); if (cur.moveToFirst()) { String id = null; String userName = null; do { id = cur.getString(cur.getColumnIndex("_id")); userName = cur.getString(cur.getColumnIndex("USER_NAME")); Log.e("TAG", "id:" + id + ";" + "userName:" + userName); } while (cur.moveToNext()); } cur.close(); // 關閉Cursor對象 } }
這樣,就是先不同應用程序間的數據共享了