http://developer.android.com/guide/topics/providers/content-providers.html
網 路上也有很多人解釋ContentProvider,這裡不多說。我的實作測試程式和網路上不同,從Android Source Code可以發現/packages/providers底下有很多個資料夾。這些大部份都不會有Acitvity,因為這類型的apk單純就只是一個介 面給其它的apk呼叫用的。所以如果實作程式將Content Provider和含Activity合成同一支apk,就比較感覺不到效果。因此測試含有2支apk
(1)MyDataBaseProvider.apk:內含2個java檔
1. MyContentProvider.java : 繼承ContentProvider,需要實作6個function
query()
insert()
update()
delete()
getType()
onCreate()
(2)UseProvider.apk :裡面有一個Main.java。這支apk和MyDataBaseProvider分開獨立的。利用系統的ContentResolver找出適合的ContentProvider溝通(本範例也就是存取DB資料)
理論上,應該是先有ContentProvider介面設計好之後,未來有需要的apk就都可以透過它去存取資料。
MyContentProvider.java的程式碼:
public class MyContentProvider extends ContentProvider {
private MyOpenHelper myOpenHelper;
private static final String[] MYCOLUMN = new String[]{ "mycolumn"};
@Override
public boolean onCreate() {
myOpenHelper = new MyOpenHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase myDatabase = myOpenHelper.getWritableDatabase();
Cursor c = myDatabase.query(uri.getLastPathSegment(), MYCOLUMN, null, null, null, null, null);
return c;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}
}
其中的getLastPathSegment目的是取出uri最後一個字段,有可能是Table的名稱也有可能是單筆資料的row id。因此可以確保異動的資料對象到底是整張Table還是某一筆資料。
MyOpenHelper.java的程式碼:
public class MyOpenHelper extends SQLiteOpenHelper {
// 定義DB相關資訊
private static final String DATABASE_NAME = "MyDatabase";
private static final int DATABASE_VERSION = 1;
private static final String TABLE_NAME = "MyTable";
public MyOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 這一個onCreate是一個callback function
// 之後程式呼叫到SQLiteOpenHelper裡的getWritableDatabase()時,
// 會檢查有無DB,沒有就先create "MyDatabase"的DB
// 然後再檢查是否要callback這個onCreate()而產生一個"MyTable"的table,並塞入一筆資料
db.execSQL("CREATE TABLE " + TABLE_NAME
+ " (id integer primary key autoincrement, mycolumn text);");
String mySql = "insert into " + TABLE_NAME
+ " (mycolumn) values('gill');";
db.execSQL(mySql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 如果DB版本更新時需要進行什麼動作,就寫在這裡
}
}
AndroidManifest.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.mydatabaseprovider"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<provider android:name="MyContentProvider"
android:authorities="com.gill.test.authorities">
</provider>
</application>
</manifest>
這邊的authorities值隨便你取,其它apk要透過這個authorities和要存取的table name組出一個URI,才可以存取DB內該table資料。
public class Main extends Activity {
// AUTHORITY要看該Provider的AndroidManifest.xml中的定義
public static final String AUTHORITY = "com.gill.test.authorities";
// URI = AUTHORITY再加table name
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/MyTable");
private static final String[] MYCOLUMN = new String[] { "mycolumn" };
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 透過getContentResolver由系統依據uri,決定要執行那一個ContentProvider
// 所以這裡不用直接呼叫MyDataBaseProvider也可以取得資料
Cursor myCursor = getContentResolver().query(CONTENT_URI, MYCOLUMN, null,
null, null);
myCursor.moveToFirst(); //一定要寫,不然會出錯
TextView txt = (TextView) findViewById(R.id.txt);
txt.setText(myCursor.getString(0));
}
}
安裝這兩支apk後,執行UseMyProvider,畫面如下:
gill是來自於DB |
如果想知道DB位置和裡面的table及資料,可以利用adb shell進入後,
# cd data/data/com.test.mydatabaseprovider/databases
# ls MyDatabase
# sqlite3 MyDatabase
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .table
MyTable android_metadata
sqlite> .header on
sqlite> select * from MyTable;
id|mycolumn1|gill
就可以看到欄位名稱和裡面的值了。
沒有留言:
張貼留言