ContentProvider应用组件实例记录
来源:互联网 发布:写jquery必须会js么 编辑:程序博客网 时间:2024/06/05 19:35
如果你公司开发了多款应用且应用间需要共享数据,如果你的应用中存在android:process=”:remote”这样的多进程的操作,是否还在忧愁如何传递数据这时候ContentProvider就可以派上用场了,贵为四大组件之一专门为不同应用不同进程共享数据使用。
首先我们需要了解URI的结构,因为ContentProvider每一个操作都跟URI有关系。
content://com.neacy.provider/books
一个典型的Uri结构的构造是以content://开头的然后接着是用于定位ContentProvider的唯一表示符,然后是路径标示,所以大体的结构体是:
content://authority-name/path-segment1/path-segment2/...
既然知道了URI的构造后如何解析呢?这里就需要引入UriMatcher类。
/** * 定义Uri匹配 */ private static final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int BOOK_COLLECT = 1; private static final int BOOK_SINGLE = 2; static { mUriMatcher.addURI(BookProviderMetaData.AUTHORITY, "books", BOOK_COLLECT); mUriMatcher.addURI(BookProviderMetaData.AUTHORITY, "books/#", BOOK_SINGLE); }
你告诉实例需要什么样的URI模式,并将对应的唯一标识符与每一个模式进行绑定,注册完这些模式之后,UriMatcher就是根据你传入的URI来进行模式匹配从而执行具体的业务代码。
switch (mUriMatcher.match(uri)) { case BOOK_COLLECT: //do something break; case BOOK_SINGLE: //do something break; }
我们实例中采用的SQLite数据库,所以我们需要先定义一个数据库需要用到的常量元数据类:
public class BookProviderMetaData { public static final String AUTHORITY = "com.neacy.provider"; public static final String DATABASE_NAME = "book.db"; public static final int DATABASE_VERSION = 1; public static final String DATABASE_TABLE = "books"; /** * BaseColums内部自己提供了一个_id字段 */ public static final class BookTableMetaData implements BaseColumns { public static final String TABLE_NAME = "books"; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/books"); public static final String BOOK_NAME = "name"; public static final String BOOK_ISBN = "isbn"; public static final String BOOK_AUTHOR = "author"; }}
然后再构建数据库帮助类:
private static class BookDataHelper extends SQLiteOpenHelper { public BookDataHelper(Context context) { super(context, BookProviderMetaData.DATABASE_NAME, null, BookProviderMetaData.DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table books (" + BookProviderMetaData.BookTableMetaData._ID + " integer primary key, " + BookProviderMetaData.BookTableMetaData.BOOK_NAME + " text, " + BookProviderMetaData.BookTableMetaData.BOOK_ISBN + " text, " + BookProviderMetaData.BookTableMetaData.BOOK_AUTHOR + " text)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("drop table if exists books"); onCreate(db); } }
然后实现ContentProvider组件并复写其中的方法来实现功能:
@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; } @Nullable @Override public String getType(Uri uri) { return null; } @Nullable @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; }
insert方法:
将数据记录插入到基础数据库中,并返回一个新创建的记录URI,数据记录采用ContentValues来存放。
public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert(BookProviderMetaData.BookTableMetaData.TABLE_NAME, null, values); Uri result = ContentUris.withAppendedId(BookProviderMetaData.BookTableMetaData.CONTENT_URI, rowId); Log.w(TAG, "insert Uri Result = " + result); getContext().getContentResolver().notifyChange(result, null); return result; }
delete方法:
根据传入的where条件把对应的数据删除并返回删除的行数。
public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int deleteId = 0; switch (mUriMatcher.match(uri)) { case BOOK_COLLECT: db.execSQL("DROP TABLE IF EXIST books"); break; case BOOK_SINGLE: String id = uri.getPathSegments().get(1); deleteId = db.delete(BookProviderMetaData.BookTableMetaData.TABLE_NAME, BookProviderMetaData.BookTableMetaData._ID + "=" + id, selectionArgs); Log.w(TAG, "delete deleteId = " + deleteId); break; } getContext().getContentResolver().notifyChange(uri, null); return deleteId; }
update方法
根据传入的ContentValues数据记录还有where条件来更新记录,并返回的是对应的行数。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int updateId = 0; switch (mUriMatcher.match(uri)) { case BOOK_SINGLE: String id = uri.getPathSegments().get(1); updateId = db.update(BookProviderMetaData.BookTableMetaData.TABLE_NAME, values, BookProviderMetaData.BookTableMetaData._ID + "=" + id, selectionArgs); Log.w(TAG, "update updateId = " + updateId); break; } getContext().getContentResolver().notifyChange(uri, null); return updateId; }
query方法
根据传入的URI或者和where语句一起返回Cursor数据:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(BookProviderMetaData.BookTableMetaData.TABLE_NAME); qb.setProjectionMap(mBookProjectMap); switch (mUriMatcher.match(uri)) { case BOOK_COLLECT: break; case BOOK_SINGLE: qb.appendWhere(BookProviderMetaData.BookTableMetaData._ID + "=" + uri.getPathSegments().get(1)); break; } SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor cursor = qb.query(db, projection, selection, selectionArgs, null, null, null); cursor.setNotificationUri(getContext().getContentResolver(), uri); Log.w(TAG, "query cursor count = " + cursor.getCount()); return cursor; }
上面我们可以看出有这么一个方法:uri.getPathSegments()返回的就是URI后面的路径值。
还有那么一个方法:
getContext().getContentResolver().notifyChange(uri, null);
这个类的作用就是操作一条数据成功的时候实时发布通知出去,一种异步监听数据库中的数据发生了变动。
private static class BookContentObserver extends ContentObserver { /** * Creates a content observer. * @param handler The handler to run {@link #onChange} on, or null if none. */ public BookContentObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); Log.w("Jayuchou", "--- onChange --- " + selfChange); /** * do something... */ } }
我们可以发现他需要一个Handler作为将参数来构造的,因为内部采用了线程所以需要Handler将结果post到主线程中去。
getContentResolver().registerContentObserver(BookProviderMetaData.BookTableMetaData.CONTENT_URI, true, mObserver);
需要的三个参数分别是:
uri—-Uri类型,是需要监听的数据库的uri.
notifyForDescendents—boolean true的话就会监听所有与此uri相关的uri。false的话则是直接特殊的uri才会监听。一般都设置为true.
observer—–ContentObserver 就是需要的contentobserver.
protected void onDestroy() { super.onDestroy(); getContentResolver().unregisterContentObserver(mObserver);// 移除监听 防止内存泄露 }
当然需要在注册界面也要有移除注册防止内存泄露。
多进程多应用调用
首先在声明被调用的ContentProvider在注册的时候需要加入
android:exported="true"
类声明这个ContentProvider可以被外部调用使用,举一个查询的例子:
Cursor c = getContentResolver().query(Uri.parse("content://com.neacy.provider/books"), null, null, null, null);
操作其实相似主要ContentProvider路径要完成即可。
最后不要忘了声明注册ContentProvider
<provider android:authorities="com.neacy.provider" android:name="com.provider.demo.BookProvider" android:exported="true"/>
这样一个ContentProvider就完成了。
- ContentProvider应用组件实例记录
- Android组件:ContentProvider实例详解
- Android应用组件之ContentProvider
- Android四大组件之一:contentprovider & 三大存储方式之一:SQLite数据库存储 应用实例
- Android四大组件之ContentProvider实现多应用之间传递数据实例
- Android四大组件之ContentProvider使用实例
- 四大应用组件之ContentProvider【Android】
- Android 四大应用组件之ContentProvider
- Jmail组件应用实例
- ASP组件应用实例
- ContentProvider组件
- ContentProvider组件
- ContentProvider实例
- ContentProvider实例
- ContentProvider 实例
- ContentProvider实例
- ContentProvider实例
- Android核心技术之(9)---四大应用组件之ContentProvider
- 【官方方法】xcode7免证书真机调试
- Double类型保留小数的n种方法
- iOS--代码片段
- Android studio 打签名包 以及在真机上编译运行
- 以后需要抽时间读,并且写读书笔记的书
- ContentProvider应用组件实例记录
- 新增的h5页面元素
- is_balance函数优化
- Mysql中用表a中数据更新另一表b中数据的同时a的数据被修改
- IIS可以最大下载2G的文件
- java反射机制基础详解
- scws 分词简单实例
- 本刊为国家级学术期刊——科技论文交流平台
- C代码从GCC到MSVC的移植