IPC机制---04 Android中的IPC通讯方式(E)

来源:互联网 发布:seo常用外链资源整理 编辑:程序博客网 时间:2024/05/16 04:39
  • 下面介绍一种IPC通讯的另外一种方式ContentProvider,这是Android中提供的专门用于不同应用间进行数据数据共享的方式。和Messenger一样,底层也是基于Binder的,但是,系统已经为我们做了封装,所以使用起来比AIDL简单多了。
  • 系统内置了许多ContentProvider,比如通讯录 短信信息等,要跨进程通信,只需要通过ContentResolver的query update insert和delete方法即可。
  • 下面创建一个BookProvider,继承自ContentProvider并实现六个抽象方法即可:
    • onCreate     代表CP的创建,一般进行初始化工作,运行在主线程,不建议执行耗时操作
    • query          查询记录,运行在CP的进程中,由外界回调并运行在Binder线程池中
    • update        更新记录,如上
    • insert          添加纪录,如上
    • delete          删除记录,如上
    • getType      返回一个Uri请求所对应的MIME类型
  • 废话不多说,直接上代码
  • package com.happy.ipc.cp.server;import android.os.Parcel;import android.os.Parcelable;/** * Created by zhonglq on 2016/3/14. */public class Book implements Parcelable {    private int id;    private String name;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(this.id);        dest.writeString(this.name);    }    public Book() {    }    protected Book(Parcel in) {        this.id = in.readInt();        this.name = in.readString();    }    public static final Creator<Book> CREATOR = new Creator<Book>() {        public Book createFromParcel(Parcel source) {            return new Book(source);        }        public Book[] newArray(int size) {            return new Book[size];        }    };}
    package com.happy.ipc.cp.server;import android.os.Parcel;import android.os.Parcelable;/** * Created by zhonglq on 2016/3/14. */public class User implements Parcelable {    private int id;    private String name;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(this.id);        dest.writeString(this.name);    }    public User() {    }    protected User(Parcel in) {        this.id = in.readInt();        this.name = in.readString();    }    public static final Creator<User> CREATOR = new Creator<User>() {        public User createFromParcel(Parcel source) {            return new User(source);        }        public User[] newArray(int size) {            return new User[size];        }    };}
    <pre name="code" class="java">package com.happy.ipc.cp.server;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;/** * Created by zhonglq on 2016/3/14. */public class DBOpenHelper extends SQLiteOpenHelper {    private static final String DB_NAME = "demo.db";    private static final int DB_VERSION = 1;    public static final String BOOK_TABLE = "book";    public static final String USER_TABLE = "user";    private String CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS " + BOOK_TABLE + " (" +            "_id INTEGER PRIMARY KEY , name TEXT)";    private String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS " + USER_TABLE + " (" +            "_id INTEGER PRIMARY KEY , name TEXT)";    public DBOpenHelper(Context context) {        super(context, DB_NAME, null, DB_VERSION);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(CREATE_BOOK_TABLE);        db.execSQL(CREATE_USER_TABLE);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

  • package com.happy.ipc.cp.server;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;import android.support.annotation.Nullable;/** * Created by zhonglq on 2016/3/14. */public class BookProvider extends ContentProvider {    private static final String AUTHORITY = "com.happy.ipc.cp.server.book.provider";    private static final String TAG = "BookProvider";    private SQLiteDatabase mDB;    private static final int BOOK_CODE = 1;    private static final int USER_CODE = 2;    private Context mContext;    private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);    static {        mUriMatcher.addURI(AUTHORITY, "book", BOOK_CODE);        mUriMatcher.addURI(AUTHORITY, "user", USER_CODE);    }    @Override    public boolean onCreate() {        mContext = getContext();        initDB();        return false;    }    private void initDB() {        mDB = new DBOpenHelper(mContext).getReadableDatabase();        mDB.execSQL("delete from " + DBOpenHelper.BOOK_TABLE);        mDB.execSQL("delete from " + DBOpenHelper.USER_TABLE);        mDB.execSQL("insert into " + DBOpenHelper.BOOK_TABLE + " values(1,'三国演义') ");        mDB.execSQL("insert into " + DBOpenHelper.BOOK_TABLE + " values(2,'红楼梦') ");        mDB.execSQL("insert into " + DBOpenHelper.USER_TABLE + " values(1,'旺财') ");        mDB.execSQL("insert into " + DBOpenHelper.USER_TABLE + " values(2,'小强') ");    }    @Nullable    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        String tableName = getTableName(uri);        return mDB.query(tableName, projection, selection, selectionArgs, null, null, sortOrder);    }    @Nullable    @Override    public String getType(Uri uri) {        return null;    }    @Nullable    @Override    public Uri insert(Uri uri, ContentValues values) {        long insert = mDB.insert(getTableName(uri), null, values);        if (insert > 0) {            mContext.getContentResolver().notifyChange(uri, null);        }        return null;    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        int delete = mDB.delete(getTableName(uri), selection, selectionArgs);        if (delete > 0) {            mContext.getContentResolver().notifyChange(uri, null);        }        return delete;    }    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        int update = mDB.update(getTableName(uri), values, selection, selectionArgs);        if (update > 0) {            mContext.getContentResolver().notifyChange(uri, null);        }        return update;    }    private String getTableName(Uri uri) {        String tableName = null;        switch (mUriMatcher.match(uri)) {            case BOOK_CODE:                tableName = DBOpenHelper.BOOK_TABLE;                break;            case USER_CODE:                tableName = DBOpenHelper.USER_TABLE;                break;            default:                throw new IllegalArgumentException("无法识别的URI");        }        return tableName;    }}
    // 客户端代码
    package com.happy.ipc.cp.client;import android.database.Cursor;import android.net.Uri;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;public class MainActivity extends AppCompatActivity {    private static final String TAG = "MainActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //以book查询为例        Uri uri = Uri.parse("content://com.happy.ipc.cp.server.book.provider/book");        Cursor cursor = getContentResolver().query(uri, null, null, null, null);        if (cursor != null && cursor.getCount() > 0) {            while (cursor.moveToNext()) {                int id = cursor.getInt(0);                String bookName = cursor.getString(1);                Log.i(TAG, " id = " + id + " ,bookName = " + bookName);            }            cursor.close();        }    }}
  • 注意
    • CRUD四个方法是存在多线程并发访问的,因此要做好线程同步
    • 本例中,只有一个SQLiteDatabase,所以不会存在什么问题
    • SQLiteDatabase内部对数据库的操作时同步处理的,如果多个SQLiteDatebase对象来操作数据库的话,就无法保证线程的同步,因为多个SQLiteDatabase对象之间无法进行线程同步
    • 如果ContentProvider的底层数据是一块内存的话,比如List,在这种情况下同List的遍历 插入 删除操作就需要进行线程同步,否则容易引起并发错误
0 0