看起來沒啥, 結果快搞死我了...
廢話不多說, 情境就是如果Android的process間要共享資源, 通常會實做ContentProvider+SQLite, 再export出適合的uri
如果想要對ContentProvider設定讀/寫的權限, 要從Manifest.xml下手, 以下範例:
ContentProvider(提供讀/寫的權限)
<manifest ...>
<application ...>
<provider
android:name="{PROVIDER_CLASS}"
android:authorities="{AUTHORITY}"
android:multiprocess="true"
android:readPermission="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}"
android:writePermission="{CONTENTPROVIDER_PACKAGE}.{WRITE_PERMISSION}>
</provider>
<activity ...></activity>
</application>
</manifest>
ContentResolver(設定為只有讀的權限)
<manifest ...>
<application ...>
<activity ...></activity>
</application>
<uses-permission android:name="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}" />
<permission-tree android:name="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}" />
<permission
android:protectionLevel="dangerous"
android:name="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}" />
</manifest>
實例說明:
ContentProvider.apk
/src/demo/content/provider/myObj.java
/src/demo/content/provider/myObjProvider.java
/src/demo/content/provider/myContentProvider.java
/res/main.xml
AndroidManifest.xml
myObj.java
package demo.content.provider;
import android.net.Uri;
import android.provider.BaseColumns;
public class myObj implements BaseColumns {
public static final String AUTHORITY = "demo.content.provider";
public static final String PATH_SINGLE = "obj/";
public static final String PATH_MULTIPLE = "objs";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH_MULTIPLE);
public static final String NAME = "name";
}
myObjProvider.java
package demo.content.provider;
import java.util.HashMap;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
public class myObjProvider extends ContentProvider {
private static final int OBJS = 1;
private static final int OBJ = 2;
public static final String DATABASE_NAME = "ContentProvider.db";
public static final String TABLE_NAME = "obj";
public static final int DATABASE_VERSION = 1;
private static UriMatcher URI_MATCHER = null;
private static HashMap<String, String> PROJECTION_MAP;
private static SQLiteDatabase db;
static {
URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
URI_MATCHER.addURI(myObj.AUTHORITY, myObj.PATH_MULTIPLE, OBJS);
URI_MATCHER.addURI(myObj.AUTHORITY, myObj.PATH_SINGLE, OBJ);
PROJECTION_MAP = new HashMap<String, String>();
PROJECTION_MAP.put(BaseColumns._ID, "_id");
PROJECTION_MAP.put(myObj.NAME, "name");
}
@Override
public boolean onCreate() {
DbHelper mDbHelper = new DbHelper(getContext());
return (db = mDbHelper.getWritableDatabase()) != null ? true : false;
}
//
// DbHelper
//
private static class DbHelper extends SQLiteOpenHelper {
private static final String DATABASE_CREATE = "CREATE TABLE " +
myObjProvider.TABLE_NAME +
"(_id INTEGER PRIMARY KEY, " +
"name TEXT UNIQUE NOT NULL)";
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DbHelper.DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
}
//
// implement abstract methods
//
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
switch (myObjProvider.URI_MATCHER.match(uri)) {
case OBJS:
count = db.delete(TABLE_NAME, selection, selectionArgs);
break;
case OBJ:
String segment = uri.getPathSegments().get(1);
String where = "";
if (selection.length() != 0) {
where = " AND (" + selection + ");";
}
count = db.delete(TABLE_NAME, "_id=" + segment + where, selectionArgs);
break;
default:
}
return count;
}
public String getType(Uri uri) {
return null;
}
public Uri insert(Uri uri, ContentValues values) {
long rowId = 0L;
ContentValues cv = null;
if (values != null) {
cv = new ContentValues(values);
} else {
cv = new ContentValues();
}
rowId = db.insert(TABLE_NAME, null, cv);
Uri result = ContentUris.withAppendedId(uri, rowId);
return result;
}
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
String orderBy = null;
switch (myObjProvider.URI_MATCHER.match(uri)) {
case OBJS:
queryBuilder.setTables(myObjProvider.TABLE_NAME);
queryBuilder.setProjectionMap(myObjProvider.PROJECTION_MAP);
break;
case OBJ:
queryBuilder.setTables(myObjProvider.TABLE_NAME);
queryBuilder.appendWhere("_id=" + uri.getPathSegments().get(1));
break;
default:
}
Cursor c = queryBuilder.query(db, projection, selection, selectionArgs, null, null, orderBy);
c.setNotificationUri(this.getContext().getContentResolver(), uri);
return c;
}
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
/*
int count = 0;
switch (myObjProvider.URI_MATCHER.match(uri)) {
case OBJ:
count = db.update(myObjProvider.TABLE_NAME, values, selection, selectionArgs);
break;
case OBJS:
String segment = uri.getPathSegments().get(1);
String where = "";
if (!TextUtils.isEmpty(selection)) {
where = " AND (" + selection + ")";
}
count = db.update(myObjProvider.TABLE_NAME, values, "_id=" + segment + where, selectionArgs);
break;
default:
}
return count;
*/
return 0;
}
}
myContentProvider.java
package demo.content.provider;
import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SimpleCursorAdapter;
public class myContentProvider extends ListActivity {
private EditText addName;
private Button addButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
addName = (EditText) findViewById(R.id.add_name);
addButton = (Button) findViewById(R.id.add_button);
addButton.setOnClickListener(new OnClickListener() {
public void onClick(View v){
add();
fillAdapter();
}
});
}
@Override
public void onStart() {
super.onStart();
fillAdapter();
}
private void fillAdapter() {
String[] projection = new String[]{myObj._ID, myObj.NAME};
ContentResolver resolver = this.getContentResolver();
Cursor mCursor = resolver.query(myObj.CONTENT_URI, projection, null, null, null);
startManagingCursor(mCursor);
String[] from = new String[]{myObj.NAME};
int[] to = new int[]{android.R.id.text1};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, mCursor, from, to);
setListAdapter(adapter);
}
private void add() {
ContentValues cv = new ContentValues();
cv.put(myObj.NAME, addName.getText().toString());
getContentResolver().insert(myObj.CONTENT_URI, cv);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginLeft="10px"
android:layout_marginBottom="5px" android:text="-Add NEW Item-" />
<EditText android:id="@+id/add_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_marginLeft="10px"
android:layout_marginBottom="5px" android:text="" />
<Button android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginLeft="10px"
android:layout_marginBottom="15px" android:text="Add" />
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="demo.content.provider"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<provider android:name="myObjProvider"
android:authorities="demo.content.provider"
android:multiprocess="true"
android:readPermission="demo.content.provider.PERMISSION.READ"
android:writePermission="demo.content.provider.PERMISSION.WRITE">
</provider>
<activity android:name=".myContentProvider"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
ContentResolver.apk(設定為有讀/寫的權限)
package demo.content.resolver;
import android.app.ListActivity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.widget.SimpleCursorAdapter;
public class myContentResolver extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String[] projection = new String[]{"_id", "name"};
Uri uri = Uri.parse("content://demo.content.provider/objs");
ContentResolver resolver = this.getContentResolver();
//
// insert
//
ContentValues cv = new ContentValues();
cv.put("name", "insert_value_by_content_resolver");
resolver.insert(uri, cv);
//
// query
//
Cursor mCursor = resolver.query(uri, projection, null, null, null);
startManagingCursor(mCursor);
String[] from = new String[]{"name"};
int[] to = new int[]{android.R.id.text1};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, mCursor, from, to);
setListAdapter(adapter);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="demo.content.resolver"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".myContentResolver"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="demo.content.provider.PERMISSION.READ"></uses-permission>
<uses-permission android:name="demo.content.provider.PERMISSION.WRITE"></uses-permission>
<permission-tree android:name="demo.content.provider.PERMISSION.READ"></permission-tree>
<permission-tree android:name="demo.content.provider.PERMISSION.WRITE"></permission-tree>
<permission android:protectionLevel="dangerous" android:name="demo.content.provider.PERMISSION.READ"></permission>
<permission android:protectionLevel="dangerous" android:name="demo.content.provider.PERMISSION.WRITE"></permission>
</manifest>
* myContentProvider.apk
here
* myContentResolver.apk
here