前言

ContentProvider为存储和获取数据提供统一的接口,它能够在不同的应用程序之间共享数据,本身就是适合进程间通信的。ContentProvider底层实现也是Binder,可是使用起来比AIDL要easy很多。系统也预制了非常多的ContentProvider,比如通讯录,音视频等,这些操作本身就是跨进程进行通信。这篇文章主要是我们来自己实现用ContentProvider来进行进程间通信,而非介绍ContentProvider怎么使用。

1. 建立数据库,方便ContentProvider使用

我们创建数据库,并创建表”game_provider.db”,里面有两个字段分别存储游戏的名字和游戏的描写叙述。

(DbOpenHelper.java)

package com.example.liuwangshu.mooncontentprovider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DbOpenHelper extends SQLiteOpenHelper {
private static final String DB_NAME="game_provider.db";
static final String GAME_TABLE_NAME="game";
private static final int DB_VERSION=1;
private String CREATE_GAME_TABLE="create table if not exists " + GAME_TABLE_NAME +"(_id integer primary key," + "name TEXT, "+"describe TEXT)";

public DbOpenHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}

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

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}
}


2. 使用ContentProvider对数据库进行操作

在initProvoder方法中,我们开启线程来对数据库进行操作。删除表的全部数据。再加入数据,并实现了query和insert方法。(GameProvider.java)

package com.example.liuwangshu.mooncontentprovider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class GameProvider extends ContentProvider {
public static final String AUTHORITY = "com.example.liuwangshu.mooncontentprovide.GameProvider";
public static final Uri GAME_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/game");
private static final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private SQLiteDatabase mDb;
private Context mContext;
private String table;

static {
mUriMatcher.addURI(AUTHORITY, "game", 0);
}

@Override
public boolean onCreate() {
table = DbOpenHelper.GAME_TABLE_NAME;
mContext = getContext();
initProvoder();
return false;
}

private void initProvoder() {
mDb = new DbOpenHelper(mContext).getWritableDatabase();
new Thread(new Runnable() {
@Override
public void run() {
mDb.execSQL("delete from " + DbOpenHelper.GAME_TABLE_NAME);
mDb.execSQL("insert into game values(1,'九阴真经ol','最好玩的武侠网游');");
}
}).start();
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
String table = DbOpenHelper.GAME_TABLE_NAME;
Cursor mCursor = mDb.query(table, projection, selection, selectionArgs, null, sortOrder, null);
return mCursor;
}

@Override
public String getType(Uri uri) {
return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
mDb.insert(table, null, values);
mContext.getContentResolver().notifyChange(uri, null);
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;
}
}


在manifest文件里,我们要让ContentProvider执行在还有一个进程,假设不大了解怎样开启进程,能够查看本系列的第一篇文章​​Android IPC机制(一)开启多进程​

<provider         android:authorities="com.example.liuwangshu.mooncontentprovide. GameProvider"
android:name=".GameProvider"
android:process=":provider"
></provider>


3. 在Activity中调用还有一个进程的GameProvider的方法

在Activity中我们在GameProvider再插入一条数据(此前GameProvider初始化时已经插入了一条数据),然后调用GameProvider的query方法来查询数据库中有几条数据并打印出来。

package com.example.liuwangshu.mooncontentprovider;

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class ContentProviderActivity extends AppCompatActivity {
private final static String TAG = "ContentProviderActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_provider);
Uri uri = Uri.parse("content://com.example.liuwangshu.mooncontentprovide.GameProvider");
ContentValues mContentValues = new ContentValues();
mContentValues.put("_id", 2);
mContentValues.put("name", "大航海时代ol");
mContentValues.put("describe", "最好玩的航海网游");
getContentResolver().insert(uri, mContentValues);
Cursor gameCursor = getContentResolver().query(uri, new String[]{"name", "describe"}, null, null, null);
while (gameCursor.moveToNext()) {
Game mGame = new Game(gameCursor.getString(0), gameCursor.getString(1));
Log.i(TAG, mGame.gameName + "---" + mGame.gameDescribe);
}
}
}


Bean文件 Game.java在​​Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用​​这篇文章中用过,直接拿过来用:

package com.example.liuwangshu.mooncontentprovider;

import android.os.Parcel;
import android.os.Parcelable;

public class Game implements Parcelable {
public String gameName;
public String gameDescribe;

public Game(String gameName, String gameDescribe) {
this.gameName = gameName;
this.gameDescribe = gameDescribe;
}

protected Game(Parcel in) {
gameName = in.readString();
gameDescribe = in.readString();
}

public static final Creator<Game> CREATOR = new Creator<Game>() {
@Override
public Game createFromParcel(Parcel in) {
return new Game(in);
}

@Override
public Game[] newArray(int size) {
return new Game[size];
}
};

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(gameName);
dest.writeString(gameDescribe);
}
}


我们执行程序,发现GameProvider执行在还有一个进程

Android IPC机制(四)用ContentProvider进行进程间通信_sqlite

log中也打印出了我们想要的结果,打出了两条游戏信息:

Android IPC机制(四)用ContentProvider进行进程间通信_数据_02