Android四大組件之Content Provider

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對象
	}

}

這樣,就是先不同應用程序間的數據共享了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章