Android四大组件之Content Provider
来源:互联网 发布:节拍器软件 编辑:程序博客网 时间:2024/05/18 00:02
Content Provider简介
1.ContentProvider是android四大组件之一,需要在AndroidManifest.xml中进行配置.2.为了在应用程序之间交换数据,android提供了ContentProvider,是不同应用程序之间进行数据交换的标准API.3.当应用程序需要把自己数据暴露给其他程序时,就可以通过提供的ContentProvider来实现.4.其他程序通过ContentResolver根据Uri去访问操作ContentProvider暴露的数据.
Content Provider开发
- 实现步骤
1.继承ContentProvider,实现query(),insert(),update()和delete()方法2.在AndroidManifest.xml文件中注册该ContentProvider,指定android:authorities
- 配置ContentProvider
<application> <provider android:name=".xxxProvider" android:authorities="com.example.provider" android:exported="true"/></application>
Content Provider使用
- Uri介绍
scheme:协议,不仅包括传统的http等网络协议,还有content://来表示本地ContentProvider所提供的数据。authority:域名部分,包括host和port,host是主机名称,port是通信端口。Android系统就是由这个部分来找到操作哪个ContentProvider。path:资源路径(数据部分),当访问者需要访问不同资源时,这个部分是动态改变的。
Android为多媒体提供的ContentProvider的Uri如下:MediaStore.Audio.Media.EXTERNAL_CONTENT_URI:存储在外置SD卡上音频内容的URIMediaStore.Audio.Media.INTERNAL_CONTENT_URI:存储在内置SD卡上音频内容的URIMediaStore.Images.Media.EXTERNAL_CONTENT_URI:存储在外置SD卡上图片文件的URIMediaStore.Images.Media.INTERNAL_CONTENT_URI:存储在内置SD卡上图片文件的URIMediaStore.Video.Media.EXTERNAL_CONTENT_URI:存储在外置SD卡上视频内容的URIMediaStore.Video.Media.INTERNAL_CONTENT_URI:存储在内置SD卡上视频内容的URIAndroid系统对联系人管理ContentProvider的几个Uri如下:ContactsContract.Contacts.CONTENT_URI:管理联系人的UriContactsContract.CommonDataKinds.Phone.CONTENT_URI:管理联系人电话的UriContactsContract.CommonDataKinds.Email.CONTENT_URI:管理联系人Email的Uri
- ContentResolver根据Uri去访问操作ContentProvider数据,ContentResolver方法如下:
insert(Uri url, ContentValues values): 向Uri对应的ContentProvider中插入values对应的数据delete(Uri url, String where, String[] selectionArgs): 删除Uri对应的ContentProvider中where提交匹配的数据update(Uri uri, ContentValues values, String where, String[] selectionArgs): 更新Uri对应的ContentProvider中where提交匹配的数据query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder): 查询Uri对应的ContentResolver中where提交匹配的数据
- ContentResolver的增删改查方法中会调用ContentProvider对应的增删改查方法,ContentProvider方法如下:
onCreate(): 在创建ContentProvider时调用insert(Uri uri, ContentValues values): 用于添加数据到指定Uri的ContentProvider中delete(Uri uri, String selection, String[] selectionArgs): 用于从指定Uri的ContentProvider中删除数据update(Uri uri, ContentValues values, String selection, String[] selectionArgs): 用于更新指定Uri的ContentProvider中的数据query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder): 用于查询指定Uri的ContentProvider,返回一个CursorgetType(Uri uri): 用于返回指定的Uri中的数据的MIME类型
- ContentResolver与ContentProvider关系图
CRUD(增删改查)方法的第一个参数都是UriUri是ContentResolver和ContentProvider进行数据交换的标识
Content Provider监听
- 实现步骤
1.继承ContentObserver基类,并重写onChange(boolean selfChange)方法2.通过ContentResolver向指定Uri注册ContentObserver监听器,在不需要时,需要对监听器取消注册
Content Provider应用实例
- 创建数据库
package com.example.provider;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "example.db"; private static final int DATABASE_VERSION = 1; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String sql = "CREATE TABLE user(_id integer primary key autoincrement,name varchar(10),phone varchar(11) NULL)"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}}
- 创建ContentProvider 来对数据库进行共享
package com.example.provider;import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.net.Uri;public class UserProvider extends ContentProvider { private DatabaseHelper mHelper; private static final UriMatcher MARCHER = new UriMatcher(UriMatcher.NO_MATCH); private static final int USERS = 1; private static final int USER = 2; private static final String AUTHORITY = "com.example.provider"; private static final String DATABASE_TABLE = "user"; /* UriMatcher工具类提供了2个方法用来确定内容提供者实际能处理的Uri: 1>.void addRUI(String authority,String path,int code):用于向UriMathcher对象注册Uri.authority和path组合成一个Uri,而code则代表该Uri对应的标识符. 2>.int match(Uri uri):根据前面注册的Uri来判断指定uri对应的标识符,如果找不到匹配的标识码就返回-1. */ static { MARCHER.addURI(AUTHORITY, "user", USERS); MARCHER.addURI(AUTHORITY, "user/#", USER); } // 该方法用于返回当前Uri所代表数据的MIME类型 // 如果操作的数据数据集合类型,MIME类型字符串应该以vnd.android.cursor.dir/开头 // 如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头 @Override public String getType(Uri uri) { switch (MARCHER.match(uri)) { case USERS: return "vnd.android.cursor.dir/user"; case USER: return "vnd.android.cursor.item/user"; default: throw new IllegalArgumentException("Wrong Uri!"); } } @Override public boolean onCreate() { mHelper = new DatabaseHelper(getContext()); return true; } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mHelper.getWritableDatabase(); long _id = db.insert(DATABASE_TABLE, null, values); if (_id > 0) sendNotifyChange(uri); return ContentUris.withAppendedId(uri, _id); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = mHelper.getWritableDatabase(); int count = db.delete(DATABASE_TABLE, selection + "=?", selectionArgs); if (count > 0) sendNotifyChange(uri); return count; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = mHelper.getWritableDatabase(); int count = db.update(DATABASE_TABLE, values, selection + "=?", selectionArgs); if (count > 0) { String name = values.getAsString("name"); sendNotifyChange(Uri.withAppendedPath(uri, name)); } return count; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = mHelper.getReadableDatabase(); Cursor mCursor = db.query(DATABASE_TABLE, projection, selection + "=?", selectionArgs, null, null, sortOrder); return mCursor; } private void sendNotifyChange(Uri uri) { getContext().getContentResolver().notifyChange(uri, null); }}
- 配置ContentProvider
<application <provider android:name="com.example.provider.UserProvider" android:authorities="com.example.provider" android:exported="true" /> </application>
- 使用Content Provider操作并监听数据
package com.example.providerdemo;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentValues;import android.content.Context;import android.database.ContentObserver;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.EditText;import android.widget.Toast;public class MainActivity extends Activity { private static final Uri USER_URI = Uri.parse("content://com.example.provider/user"); private ContentResolver mResolver; private Context mContext; private EditText name, phone; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 0x123) { show("Date Changed!"); } } }; private ContentObserver observer = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { mHandler.sendEmptyMessage(0x123); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mResolver = getContentResolver(); mContext = MainActivity.this; name = (EditText) findViewById(R.id.name); phone = (EditText) findViewById(R.id.phone); Uri uri = Uri.withAppendedPath(USER_URI, "xiaoming"); mResolver.registerContentObserver(uri, false, observer); } @Override protected void onDestroy() { super.onDestroy(); mResolver.unregisterContentObserver(observer); } public void insert(View view) { ContentValues values = new ContentValues(); values.put("name", name.getText().toString()); values.put("phone", phone.getText().toString()); Uri result = mResolver.insert(USER_URI, values); if (result != null) { show("Insert success!"); } } public void delete(View view) { String whereClause = "name"; String[] whereArgs = {name.getText().toString()}; int result = mResolver.delete(USER_URI, whereClause, whereArgs); if (result > 0) { show("Delete success!"); } } public void update(View view) { ContentValues values = new ContentValues(); values.put("name", name.getText().toString()); values.put("phone", phone.getText().toString()); String whereClause = "name"; String[] whereArgs = {name.getText().toString()}; int result = mResolver.update(USER_URI, values, whereClause, whereArgs); if (result > 0) { show("Update success!"); } } public void query(View view) { String[] columns = {"_id", "name", "phone"}; String whereClause = "name"; String[] whereArgs = {name.getText().toString()}; Cursor result = mResolver.query(USER_URI, columns, whereClause, whereArgs, null); if (result.moveToFirst()) { String mPhone = result.getString(result.getColumnIndex("phone")); show("query success. Phone:" + mPhone); } } private void show(String str) { Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show(); }}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/phone" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="insert" android:text="Insert" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="delete" android:text="Delete" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="update" android:text="Update" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="query" android:text="Query" /></LinearLayout>
Content Provider实现原理
- Content Provider启动流程
第一次访问Content Provider时启动
- Content Provider数据共享原理
原理概要1.Content Provider组件将要传输的共享数据抽象为一个游标2.Content Provider组件通过Binder进程间通信机制来突破应用程序为边界的权限控制3.以匿名共享内存作为数据传输媒介,从而提供了一种高效的数据共享方式
概要流程xxActivity组件在请求xxProvider组件返回信息之前,首先在当前应用程序创建一个CursorWindow对象,CursorWindow内部包含了一块匿名共享内存。通过Binder进程间通信机制将所创建的CursorWindow对象(连同它内部的匿名共享内存)传递给xxProvider组件。xxProvider组件获得了xxActivity组件发送过来的CursorWindow对象之后,就会创建一个SQLiteCursor对象通过调用setWindow将CursorWindow对象保存在父类的成员变量mWindow中。SQLiteCursor对象创建完成之后,xxProvider组件就会将xxActivity组件所请求的数据保存在这个SQLiteCursor对象中实际上是保存在与它所关联的CursorWindow对象内部的一块匿名共享内存中xxActivity可以访问这块匿名共享内存,因此可以通过这块内存来获取xxProvider组件返回给它的数据。SQLiteCursor对象并不是一个Binder本地对象,xxProvider组件不能直接将它返回给xxActivity组件使用。xxProvider组件首先会创建一个CursorToBulkCursorAdaptor对象,用来适配前面创建的SQLiteCursor对象,并将这个对象保存在mCursor中然后将CursorToBulkCursorAdaptor对象返回给xxActivity组件。xxActivity组件收到xxProvider组件返回数据之前,除了创建CursorWindow对象外,还会创建一个BulkCursorToCursorAdaptor对象并将CursorWindow对象保存在它的父类AbstractWindowedCursor的成员变量mWindow中。xxActivity组件收到xxProvider组件返回的CursorToBulkCursorAdaptor对象之后,实际上获得的是CursorToBulkCursorAdaptor的代理对象并将它保存BulkCursorToCursorAdaptor对象的mBulkCursor中,这时候xxActivity组件就可以通过这个BulkCursorToCursorAdaptor对象来读取xxProvider组件返回的数据了。
SQLiteCursor类实现关系图注意:CursorWindow包含了一块匿名共享内存
Content Provider 数据共享模型注意:CursorWindow引用了同一块匿名共享内存
实现原理结构图
- Content Provider数据监听原理
原理概要1.ContentProvider组件的数据更新通知机制类似于Android系统的广播机制,都是一种消息发布和订阅的事件驱动模型。2.内容观察者ContentObserver负责接收数据更新通知,ContentProvider组件负责发送数据更新通知。3.内容观察者ContentObserver在接收到通知之前,必须要注册到ContentService中,通过URI来描述需要接收什么样的数据更新通知。
注册ContentObserver注意:1.真正注册到ContentService中的并不是一个ContentObserver,而是与这个ContentObserver所关联的binder本地对象Transport(ContentObserver contentObserver)2.mRootNode保存内容观察者
发送数据改变通知
回调onChange方法
数据监听结构图
1 0
- Android四大组件之Content Provider
- Android四大基本组件之Content Provider
- Android四大组件之Content Provider
- Android四大组件之Content Provider
- Android 四大组件之 Content Provider
- Android 四大组件之Content provider使用
- Android四大组件之自定义Content Provider
- Android 四大组件之Content Provider
- Android四大组件之Content Provider
- Android四大组件之Content Provider
- Android四大组件之Content Provider
- android的四大组件之Content Provider
- 四大组件之Content Provider
- Android 四大组件 之 content provider 创建流程
- Android四大组件之Content Provider(内容提供者)
- Android四大组件之 内容提供器Content Provider
- Android笔记---四大组件之Content Provider内容提供者详解
- Android四大组件之内容提供者Content Provider总结
- sublime text安装ctags定位函数
- Android 编程技巧之 ----- 随意从当前 Activity 退出应用
- 压测总结
- mac使用技巧
- Tracking-Learning-Detection原理分析
- Android四大组件之Content Provider
- TLD算法学习之L-K光流法理论篇二
- Explosive
- AD14中自定义PCB板形状
- 从一个有趣的题目理解享元模式
- 黑马程序员__java之多线程上
- Leetcode 8 - String to Integer (atoi)
- Gradle中productFlavors的使用指南
- Hdu 2039(水题) 解题报告