浅谈Android四大组件之ContentProvider
16lz
2021-01-26
1 介绍
ContentProvider作为Android中的四大组件之一其主要作用是暴露出私有的数据供其它应用使用,比如一个应用程序需要读取手机里的手机联系人供自己使用。由此我们可以知道,这是也是一种Android中进程之间的通信方式。内容提供者在开发中自己写不多。更多的是访问内容提供者,一般都是访问系统的内容提供者
2 简单案例
新建一个应用工程,实现sqllite初始化:
public class MySqliteopenhelper extends SQLiteOpenHelper { public MySqliteopenhelper(Context context) { super(context, "test.db", null, 1); // TODO Auto-generated constructor stub } //第一次创建的时候调用 //特别适合 初始化 @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table person (_id integer primary key autoincrement,name varchar(20),age varchar(20) )"); db.execSQL("insert into person (name,age) values('赵日天','9')"); db.execSQL("insert into person (name,age) values('刘斩仙','10')"); db.execSQL("insert into person (name,age) values('李杀神','7')"); db.execSQL("insert into person (name,age) values('王诛魔','8')"); } //版本更新的时候调用 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub } }
新建ContentProvider实现类MyProvider:
public class MyProvider extends ContentProvider { private static final int QUERY = 1; // 1.在清单文件中配置 需要android:authorities="cn.test.provider" android 4.4以上版本需要额外配置 android:exported="true" // 2.添加uri的匹配器 private static final UriMatcher urimatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int INSERT = 2; private static final int DELETE = 3; private static final int UPDATE = 4; private MySqliteopenhelper helper; static { // authority 就是在清单文件中配置 的android:authorities="cn.test.provider" // authority 相当于主机名 www.baidu.com // path 二级路径 相当于 www.baidu.com/news 的news // code 匹配成功以后的返回码 必须正数 urimatcher.addURI("cn.test.provider", "query", QUERY); urimatcher.addURI("cn.test.provider", "insert", INSERT); urimatcher.addURI("cn.test.provider", "delete", DELETE); urimatcher.addURI("cn.test.provider", "update", UPDATE); } @Override public boolean onCreate() { // getContext() 内容提供者获取 上下文的方法 helper = new MySqliteopenhelper(getContext()); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 匹配uri 匹配成功了以后才去 操作数据库 int match = urimatcher.match(uri); if (match == QUERY) { SQLiteDatabase db = helper.getReadableDatabase(); // projection 要查询的列名 Cursor cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder); //数据不要关// db.close(); return cursor; } else { throw new IllegalArgumentException("大熊第!你的uri 好像有点问题哦"); } } @Override public Uri insert(Uri uri, ContentValues values) { // 判断 匹配码 int match = urimatcher.match(uri); if (match == INSERT) { SQLiteDatabase db = helper.getWritableDatabase(); // insert2 数据添加到了 第几行 long insert2 = db.insert("person", null, values); db.close(); return Uri.parse("cn.test/" + insert2); } else { throw new IllegalArgumentException("大兄弟!你的暗号没对上哦"); } } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { if (urimatcher.match(uri) == DELETE) { SQLiteDatabase db = helper.getWritableDatabase(); // 刪除 delete2 刪除影响了几行 int delete2 = db.delete("person", selection, selectionArgs); db.close(); return delete2; } return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { if (urimatcher.match(uri) == UPDATE) { SQLiteDatabase db = helper.getWritableDatabase(); // 更新数据 update2 修改影响力几行 int update2 = db.update("person", values, selection, selectionArgs); db.close(); return update2; } return 0; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; }}
注册清单:
<provider android:name="cn.test.whycontentprovider.MyProvider" android:authorities="cn.test.provider" android:exported="true"> provider>
这时我们再新建一个新的应用工程写四个按钮实现对内容提供者的查询,增加,删除,修改操作:
// 内容提供者查询其他应用的数据库
public void click1(View v) { // content:// uri前面必须要添加 Uri uri = Uri.parse("content://cn.test.provider/query"); // 获取内容解析者 Cursor cursor = getContentResolver().query(uri, null, null, null, null); while (cursor.moveToNext()) { String _id = cursor.getString(0); String name = cursor.getString(1); String age = cursor.getString(2); System.out.println("内容提供者查询的数据" + " " + _id + " " + name + " " + age); } cursor.close(); } // 内容提供者增加其他应用的数据库 public void click2(View v) { Uri url = Uri.parse("content://cn.test.provider/insert"); ContentValues values = new ContentValues(); values.put("name", "叶良辰"); values.put("age", "15"); // 获取内容解析者 Uri insert = getContentResolver().insert(url, values); System.out.println(insert); } // 内容提供者删除其他应用的数据库 public void click3(View v) { Uri url = Uri.parse("content://cn.test.provider/delete"); int delete = getContentResolver().delete(url, "_id=?", new String[] { "2" }); System.out.println(delete); } // 内容提供者修改其他应用的数据库 public void click4(View v) { Uri url = Uri.parse("content://cn.test.provider/update"); ContentValues values = new ContentValues(); values.put("age", "99"); int update = getContentResolver().update(url, values, "_id=?", new String[] { "1" }); System.out.println(update); }
3 内容提供者案例-读取联系人
步骤 :
首先 查询 raw_contacts 表 查到contact_id 就是data表 raw_contact_id
然后 根据raw_contact_id 查询data1 和mimetype
最后 根据mimetype 来区分data1的内容
/** * 通过 内容提供者查询联系人 * * @param context * 上下文 * * @return 联系人的集合 */ public List queryContacts(Context context) { List infos = null; // 1 查询raw_contacts 表 查询contact_id // 1>查询raw_contacts 的uri 去源码 清单文件和 源码找到路径 // android:authorities="contacts;com.android.contacts" contacts 以前使用 // com.android.contacts 新的authorities // matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", // RAW_CONTACTS); // 2 根据查到的contact_id 也就是 data 表中的 raw_contact_id去查询data表 查询 data1 // mimetype // 3使用mimetype_id 去区分查到的 data1的数据 Uri uri = Uri.parse("content://com.android.contacts/raw_contacts"); Uri datauri = Uri.parse("content://com.android.contacts/data"); /// 1 查询raw_contacts 表 查询contact_id 全查询出来 Cursor cursor = context.getContentResolver().query(uri, new String[] { "contact_id" }, null, null, null); if (cursor != null && cursor.getCount() > 0) { // 初始化集合 infos = new ArrayList<>(); while (cursor.moveToNext()) { String contact_id = cursor.getString(0); System.out.println(contact_id); // 查询所有的列名 // Cursor cursor2 = getContentResolver().query(datauri, null, // null, null, null); // //查询cursor中的所有的列名 // String[] columnNames = cursor2.getColumnNames(); // for (String string : columnNames) { // System.out.println(string); // } // 没查询到一个contact_id 都要去查一次 data表 查 data1 和 mimetype_id // mimetype_id 在data表中并没有 而是有mimetype //记得进行非空判断 数据库并没有删除这条数据 而是置为null if (contact_id!=null) { Cursor datacursor = context.getContentResolver().query(datauri, new String[] { "data1", "mimetype" }, "raw_contact_id=?", new String[] { contact_id }, null); if (datacursor != null && datacursor.getCount() > 0) { // 这里进来说明有联系人的数据 可以创建联系人的对象 ContactInfo info = new ContactInfo(); // 循环取出每条数据 // 循环取出 while (datacursor.moveToNext()) { String data1 = datacursor.getString(0); String mimetype = datacursor.getString(1); // 3 使用mimetype 区分获取的数据 if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { // System.out.println("联系人的电话是:" + data1); info.setPhone(data1); } if (mimetype.equals("vnd.android.cursor.item/name")) { // System.out.println("联系人的姓名是:" + data1); info.setName(data1); } if (mimetype.equals("vnd.android.cursor.item/nickname")) { // System.out.println("联系人的昵称是:" + data1); info.setNickname(data1); } if (mimetype.equals("vnd.android.cursor.item/email_v2")) { // System.out.println("联系人的邮箱是:" + data1); info.setEmail(data1); } } datacursor.close(); infos.add(info); } } } } cursor.close(); return infos; }
4 内容观察者
内容观察者是为了在内容提供者处通知
内容使用处:
Uri uri=Uri.parse("content://cn.test.provider/query"); //注册内容观察者 通过 内容解析者 //notifyForDescendents ture 不是非常严格 检测URI 和false 非常严格检查uri getContentResolver().registerContentObserver(uri, true, new MyContenObserver(new Handler())); class MyContenObserver extends ContentObserver{ //handler 需要更新UI public MyContenObserver(Handler handler) { super(handler); // TODO Auto-generated constructor stub } //selfChange 是否是自己应用的内容提供者发生变化 @Override public void onChange(boolean selfChange) { super.onChange(selfChange); System.out.println("数据库发生了变化"); } }
内容提供者
提供数据处
`getContext().getContentResolver().notifyChange(uri,null);`
observer 是否指定专门的观察者 null 不指定专门的观察者。
更多相关文章
- [转]android 系统权限大全的简介与内容
- [android开发之内容更新类APP]三、项目的基本功能之布局
- android百度地图api实现查询经过某站点的所有公交路线
- Android(安卓)解决NestedScrollView底部内容被遮挡显示不全
- Android逆向入门1——引言与抓包
- 在Android(安卓)Studio中查看Sqlite数据内容的方法
- Android在相册中过滤GIF图片
- Android(安卓)EditText加载HTML内容(内容包含网络图片)
- android应用基础--由官方帮助文件翻译