IPC机制之使用ContentProvider

IPC机制之使用ContentProvider

我们知道在Android中,ipc机制的基础概念中主要包括了三个方面的内容:
- 1、Serializable
- 2、Parceable
- 3、Binder
对于上述中的三个内容再次就不再详述,今天我们要讲的是另一个我们经常用的东西但是很容易忽视它,我们经常操作的一些东西,比如说打电话、发短信、查看日程表信息……,或许你可能已经猜到了,没错,它就是我们常说的内容提供者(ContentProvider)
在接触Android之初,老师常常教我们四大组件(Activity、Service、Broadcast、ContentProvider),或许我们对activity并不陌生,比较看到的东西都可以称之为activity。好了,言归正传。
ContentProvider,如果你去看源码就会发现它的底层还是实现的是Binder,虽然它的底层是实现的Binder,但是它的使用过程比AIDL简单,这是因为系统已经为我们封装好了。
通过源码我们发现它有如下几个必定会实现的方法:

      public abstract boolean onCreate();      
     public abstract Uri insert( Uri uri, ContentValues values);
     public abstract int delete(Uri uri, String selection,String[] selectionArgs);
      public abstract int update( Uri uri, @Nullable ContentValues values,String selection,  String[] selectionArgs);
     public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder, CancellationSignal cancellationSignal) {
        return query(uri, projection, selection, selectionArgs, sortOrder);
    }          
     public abstract Cursor query(Uri uri,String[] projection, String selection,String[] selectionArgs, String sortOrder)
     public abstract  String getType( Uri uri);

其实对于这6个抽象方法(虽然写了7个)都很好理解,除了onCreate和getType方法,其他的四个方法是不是和数据库中的CRUD一样呢,即数据库的增删改查功能。onCreate()代码ContentProvider的创建,getType()用于返回一个Uri请求所对应的MIME类型。


下面看一个简单的例子,它演示了ContentProvider的工作过程,我们创建一个类,它继承自ContentProvider并实现了上述中的6个必要抽象方法。

package com.example.userdefindcontentproviderdemo;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;

public class BookProvider extends ContentProvider {
    private static  final String TAG="BookProvider";

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        Log.d(TAG, "onCreate,current thread:"+Thread.currentThread().getName());
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        Log.d(TAG, "query,current thread:"+Thread.currentThread().getName());
        return null;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        Log.d(TAG, "getType()");
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        Log.d(TAG, "insert,current thread:"+Thread.currentThread().getName());
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        Log.d(TAG, "delete,current thread:"+Thread.currentThread().getName());
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        // TODO Auto-generated method stub
        Log.d(TAG, "onCreate,current thread:"+Thread.currentThread().getName());
        return 0;
    }

}

当然为了我们能够使用它,也要和service一样进行注册才可以使用,这里建议加上包名,可以方便外界的访问。
在manifest文件中添加如下代码:

<provider             android:name="com.example.userdefindcontentproviderdemo.BookProvider"        android:authorities="com.example.userdefindcontentproviderdemo.provider"
android:permission="com.example.PROVIDER"
android:process=":progress" >
</provider>

注册了ContentProvider后,我们就可以在外部应用中访问它了

package com.example.userdefindcontentproviderdemo;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Uri    uri=Uri.parse("content://com.example.userdefindcontentproviderdemo.provider");
        getContentResolver().query(uri, null, null, null, null);
        getContentResolver().query(uri, null, null, null, null);
        getContentResolver().query(uri, null, null, null, null);
    }
}

上面代码通过getContentResolver对象的query方法去查询了BookProvider中的数据,其中用content://com.example.userdefindcontentproviderdemo.provider作为BookProvider的唯一标识。
到目前为止,整个ContentProvider流程已经跑通了。下面我们来完善BookProvider,让它能对外部提供数据。为了更好的展示数据信息,我们需要一个数据库用于管理图书和用户信息。

package com.example.userdefindcontentproviderdemo;
import android.R.integer;
import android.R.string;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class DBOpenHelper extends SQLiteOpenHelper {
    public static final String DB_NAME = "bookprovider.db";
    public static final String BOOK_TABLE_NAME = "book";
    public static final String USER_TABLE_NAME = "user";
    public static final int DB_VERSION = 1;

    private String CREATE_BOOK_TABEL = "create table if not exists" + BOOK_TABLE_NAME + "(_id integer primary key," + "name text)";

    private String CREATE_USER_TABEL = "create table if not exists"+ USER_TABLE_NAME + "(_id integer primary key," + "name text,"+ "sex int)";

    public DBOpenHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        // TODO Auto-generated constructor stub
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK_TABEL);
        db.execSQL(CREATE_USER_TABEL);
        // TODO Auto-generated method stub

    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub

    }
}

上面的代码就是一个最简单的数据库的简单实现,实现数据库的创建和更新,现在我们可以通过使用UriMatcher匹配想要访问的表。现在将BookProvider类修改如下:

public class BookProvider extends ContentProvider {
    private static final String TAG = "BookProvider";
    private static final String AUTHORITIES = "com.example.userdefindcontentproviderdemo.provider";
    private static final Uri BOOK_CONTENT_URI = Uri.parse("content://"
            + AUTHORITIES + "/book");
    private static final Uri USER_CONTENT_URI = Uri.parse("content://"
            + AUTHORITIES + "/user");
    private static final int BOOK_URI_CODE = 0;
    private static final int USER_URI_CODE = 1;
    private static final UriMatcher sURIM_MATCHER = new UriMatcher(
            UriMatcher.NO_MATCH);
    static {
        sURIM_MATCHER.addURI(AUTHORITIES, "book", BOOK_URI_CODE);
        sURIM_MATCHER.addURI(AUTHORITIES, "user", USER_URI_CODE);
    }

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        Log.d(TAG, "onCreate,current thread:"
                + Thread.currentThread().getName());
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        Log.d(TAG, "query,current thread:" + Thread.currentThread().getName());
        return null;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        Log.d(TAG, "getType()");
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        Log.d(TAG, "insert,current thread:" + Thread.currentThread().getName());
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        Log.d(TAG, "delete,current thread:" + Thread.currentThread().getName());
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        // TODO Auto-generated method stub
        Log.d(TAG, "onCreate,current thread:"
                + Thread.currentThread().getName());
        return 0;
    }

}

从上面这段代码中分别指定了book和user表的Uri,所关联的Uri_code分别是0和1,是通过下面的过程关联上来的:

static {
        sURIM_MATCHER.addURI(AUTHORITIES, "book", BOOK_URI_CODE);
        sURIM_MATCHER.addURI(AUTHORITIES, "user", USER_URI_CODE);
    }

最后BookProvider的完整代码如下:

package com.example.userdefindcontentproviderdemo;

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.util.Log;

public class BookProvider extends ContentProvider {
    private static final String TAG = "BookProvider";
    private static final String AUTHORITIES = "com.example.userdefindcontentproviderdemo.provider";
    private static final Uri BOOK_CONTENT_URI = Uri.parse("content://"
            + AUTHORITIES + "/book");
    private static final Uri USER_CONTENT_URI = Uri.parse("content://"
            + AUTHORITIES + "/user");
    private static final int BOOK_URI_CODE = 0;
    private static final int USER_URI_CODE = 1;
    private static final UriMatcher sURIM_MATCHER = new UriMatcher(
            UriMatcher.NO_MATCH);
    static {
        sURIM_MATCHER.addURI(AUTHORITIES, "book", BOOK_URI_CODE);
        sURIM_MATCHER.addURI(AUTHORITIES, "user", USER_URI_CODE);
    }

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        Log.d(TAG, "onCreate,current thread:"
                + Thread.currentThread().getName());
        return false;
    }

    private Context mContext;
    private SQLiteDatabase mDb;

    private void initProviderData() {
        mDb = new DBOpenHelper(mContext).getWritableDatabase();
        mDb.execSQL("delete from " + DBOpenHelper.BOOK_TABLE_NAME);
        mDb.execSQL("delete from " + DBOpenHelper.USER_TABLE_NAME);
        mDb.execSQL("insert into book values(3,'android');");
        mDb.execSQL("insert into book values(4,'ios');");
        mDb.execSQL("insert into book values(5,'html5');");
        mDb.execSQL("insert into user values(1,'jack',1);");
        mDb.execSQL("insert into book values(2,'tom'),2;");
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        String table = getTableName(uri);
        if (table == null) {
            throw new IllegalArgumentException("UnSupported URI:" + uri);
        }
        return mDb.query(table, projection, selection, selectionArgs, null,
                sortOrder, null);
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        Log.d(TAG, "getType()");
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        String table = getTableName(uri);
        if (table == null) {
            throw new IllegalArgumentException("UnSupported URI:" + uri);
        }

        mDb.insert(table, null, values);
        mContext.getContentResolver().notifyChange(uri, null);
        return uri;

    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        String table = getTableName(uri);
        if (table == null) {
            throw new IllegalArgumentException("UnSupported URI:" + uri);
        }
        int count = mDb.delete(table, selection, selectionArgs);
        if (count > 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return count;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        // TODO Auto-generated method stub
        String table = getTableName(uri);
        if (table == null) {
            throw new IllegalArgumentException("UnSupported URI:" + uri);
        }
        int row = mDb.update(table, values, selection, selectionArgs);
        if (row > 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }

        return row;
    }

    private String getTableName(Uri uri) {
        String tableNameString = null;
        switch (sURIM_MATCHER.match(uri)) {
        case BOOK_URI_CODE:
            tableNameString = DBOpenHelper.BOOK_TABLE_NAME;
        case USER_URI_CODE:
            tableNameString = DBOpenHelper.USER_TABLE_NAME;
            break;

        default:
            break;
        }
        return tableNameString;
    }
}

在此需要注意的是:query、insert、update、delete这四个方法是存在多线程并发访问的,因此在方法内部需要做好线程同步。
ok,现在我们在activity中调用它一下看看效果。

package com.example.userdefindcontentproviderdemo;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {
    private static final String TAG_STRING = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Uri bookUri = Uri
                .parse("content://com.example.userdefindcontentproviderdemo.provider/book");
        ContentValues values = new ContentValues();
        values.put("_id", 6);
        values.put("name", "开发者探索");
        getContentResolver().insert(bookUri, values);
        Cursor bookCursor = getContentResolver().query(bookUri,
                new String[] { "_id", "name" }, null, null, null);
        while (bookCursor.moveToNext()) {
            Book book = new Book();
            book.bookId = bookCursor.getInt(0);
            book.bookName = bookCursor.getString(1);
            Log.i(TAG_STRING, "query book:" + book.toString());

        }
        bookCursor.close();

        Uri userUri = Uri
                .parse("content://com.example.userdefindcontentproviderdemo.provider/user");
        Cursor userCursor = getContentResolver().query(userUri,
                new String[] { "_id", "name", "sex" }, null, null, null);
        while (userCursor.moveToNext()) {
            User user = new User();
            user.userId = userCursor.getInt(0);
            user.userName = userCursor.getString(1);
            user.isMale = userCursor.getInt(2) == 1;
            Log.i(TAG_STRING, user.toString());
        }
        userCursor.close();

    }

}

到此为止我们的代码编写就完成了,当然这上面有俩个实体类很简单就没有贴代码了。
写到这里不知道你是否对ContentProvider有了进一步的了解了呢?希望能对你自己定义ContentProvider有一些的帮助。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值