ContentProvider 使用详解
极力推荐文章:欢迎收藏
Android 干货分享
阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android
本篇文章主要介绍 Android
开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:
- ContentProvider
- 获取联系人信息的方法
- 获取短信内容的方法
- ContentResolver 内容解析者
- ContentObserver 内容观察者
- ContentProvider ContentResolver ContentObserver 三者关系
ContentProvider
是Android
四大组件之一,其本质上是一个标准化的数据管道,它屏蔽了底层的数据管理和服务等细节,以标准化的方式在Android
应用间共享数据。用户可以灵活实现ContentProvider
所封装的数据存储以及增删改查等,所有的ContentProvider
必须实现一个对外统一的接口(URI)
。
1. ContentProvider 实现
ContentProvider 继承关系
java.lang.Object
↳ android.content.ContentProvider
四大组件之一,必须在Androidmainfest.xml 中注册
<provider
android:name="com.programandroid.CustomContentProviderMethod"
android:authorities="ProgramAndroid"
android:exported="true" />
注意 :
URI 中的元素
android:authorities="ProgramAndroid"
继承 ContentProvider 实现增删改查等方法
package com.programandroid.ContentProvider;
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;
import android.support.annotation.Nullable;
/*
* ContentProviderMethod.java
*
* Created on: 2017-9-13
* Author: wangjie
*
* Welcome attention to weixin public number get more info
*
* WeiXin Public Number : ProgramAndroid
* 微信公众号 :程序员Android
*
*/
public class CustomContentProviderMethod extends ContentProvider {
private SQLiteDatabase db;
private static final String MAUTHORITIESNAME = "ProgramAndroid";
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int PERSON = 1;
private static final int PERSON_NUMBER = 2;
private static final int PERSON_TEXT = 3;
private static final String TABLE_NAME = "table_person";
// 构建URI
static {
// content://programandroid/person
matcher.addURI(MAUTHORITIESNAME, "person", PERSON);
// # 代表任意数字content://programandroid/person/4
matcher.addURI(MAUTHORITIESNAME, "person/#", PERSON_NUMBER);
// * 代表任意文本 content://programandroid/person/filter/ssstring
matcher.addURI(MAUTHORITIESNAME, "person/filter/*", PERSON_TEXT);
}
@Override
public boolean onCreate() {
DBHelper helper = new DBHelper(getContext());
// 创建数据库
db = helper.getWritableDatabase();
return true;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// 过滤URI
int match = matcher.match(uri);
switch (match) {
case PERSON:
// content://autoname/person
return db.query(TABLE_NAME, projection, selection, selectionArgs,
null, null, sortOrder);
case PERSON_NUMBER:
break;
case PERSON_TEXT:
break;
default:
break;
}
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
// 过滤URI
int match = matcher.match(uri);
switch (match) {
case PERSON:
// content://autoname/person
long id = db.insert(TABLE_NAME, null, values);
// 将原有的uri跟id进行拼接从而获取新的uri
return ContentUris.withAppendedId(uri, id);
case PERSON_NUMBER:
break;
case PERSON_TEXT:
break;
default:
break;
}
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;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
}
提供对外提供操作的数据库方法
package com.programandroid.ContentProvider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
/*
* DBHelper.java
*
* Created on: 2017-9-13
* Author: wangjie
*
* Welcome attention to weixin public number get more info
*
* WeiXin Public Number : ProgramAndroid
* 微信公众号 :程序员Android
*
*/
public class DBHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "persons.db";
private static final int DB_VERSION = 1;
private static final String TABLE_NAME = "table_person";
private static final String ID = "_id";
private static final String NAME = "name";
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE " + TABLE_NAME + "(" + ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" + "," + NAME
+ " CHAR(10) )";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
其他APK 访问此ContentProvider 数据库的方法
public class MainActivity extends Activity {
private String uri = "content://ProgramAndroid/person";
private EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) findViewById(R.id.ed_name);
}
public void QureyData(View view) {
String name = null;
Cursor cursor = getContentResolver().query(Uri.parse(uri), null, null, null, null);
while (cursor.moveToNext()) {
name = cursor.getString(cursor.getColumnIndex("name"));
}
mEditText.setText(name);
}
public void InsertData(View view) {
String editName = mEditText.getText().toString();
ContentValues values = new ContentValues();
values.put("name, editName);
Uri result = getContentResolver().insert(Uri.parse(uri), values);
// 注意 : 此条添加上才ContentObserver可以监听数据库改变
getContentResolver().notifyChange(Uri.parse(uri),null);
long parseid = ContentUris.parseId(result);
if (parseid > 0) {
Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_LONG).show();
mEditText.setText("");
}
}
}
注意 :
// 此条添加上才ContentObserver可以监听数据库改变
getContentResolver().notifyChange(Uri.parse(uri),null);
至此,自定义ContentProvider
的使用方法已经实现。
2. 获取联系人信息的方法
Android
系统自带一下ContentProvider
,比如 联系人
例如: 源码 packages\providers
下的内容
本段主要实现获取系统联系人(ContactProvider)
提供的一些信息
获取联系人实现方法
public class ContactListActivity extends Activity {
private static final String tag = "ContactListActivity";
private ListView lv_contact_list;
private List<HashMap<String, String>> mContactList = new ArrayList<HashMap<String, String>>();
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
// 给数据适配器设置数据
MyAdapter myAdapter = new MyAdapter();
TextView emptyView = new TextView(getApplicationContext());
emptyView.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
emptyView.setText(getResources().getString(
R.string.please_add_contanct));
emptyView.setVisibility(View.GONE);
emptyView.setTextColor(Color.BLACK);
emptyView.setTextSize(20);
emptyView.setGravity(Gravity.CENTER);
((ViewGroup) lv_contact_list.getParent()).addView(emptyView);
lv_contact_list.setEmptyView(emptyView);
lv_contact_list.setAdapter(myAdapter);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_list);
initUI();
initData();
}
/**
* 从系统数据库中获取联系人数据,权限,读取联系人
*/
private void initData() {
new Thread() {
public void run() {
// 1,获取内容解析器(访问地址(后门))
ContentResolver contentResolver = getContentResolver();
// 2,对数据库指定表进行查询操作
Cursor cursor = contentResolver.query(Uri
.parse("content://com.android.contacts/raw_contacts"),
new String[] { "contact_id" }, null, null, null);
// 3,判断游标中是否有数据,有数据一直度
while (cursor.moveToNext()) {
String id = cursor.getString(0);
Log.i(tag, "id = " + id);// 1,2,3
// 4,通过此id去关联data表和mimetype表生成视图,data1(数据),mimetype(数据类型)
Cursor indexCursor = contentResolver.query(
Uri.parse("content://com.android.contacts/data"),
new String[] { "data1", "mimetype" },
"raw_contact_id = ?", new String[] { id }, null);
HashMap<String, String> hashMap = new HashMap<String, String>();
// 5,游标向下移动获取数据过程
while (indexCursor.moveToNext()) {
String data = indexCursor.getString(0);
String type = indexCursor.getString(1);
// Log.i(tag, "data = "+data);
// Log.i(tag, "type = "+type);
if (type.equals("vnd.android.cursor.item/phone_v2")) {
// data就为电话号码
hashMap.put("phone", data);
} else if (type.equals("vnd.android.cursor.item/name")) {
// data 为联系人名字
hashMap.put("name", data);
}
}
indexCursor.close();
mContactList.add(hashMap);
}
cursor.close();
// 告知主线程集合中的数据以及准备完毕,可以让主线程去使用此集合,填充数据适配器
mHandler.sendEmptyMessage(0);
};
}.start();
}
private void initUI() {
lv_contact_list = (ListView) findViewById(R.id.lv_contact_list);
lv_contact_list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// 1,position点中条目的索引值,集合的索引值
String phone = mContactList.get(position).get("phone");
// 2,将此电话号码传递给前一个界面
Intent intent = new Intent();
intent.putExtra("phone", phone);
setResult(0, intent);
// 3,关闭此界面
finish();
}
});
}
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return mContactList.size();
}
@Override
public HashMap<String, String> getItem(int position) {
return mContactList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
if (convertView == null) {
holder = new Holder();
// 1,生成当前listview一个条目相应的view对象
convertView = View.inflate(getApplicationContext(),
R.layout.list_item_contact, null);
// 2,找到view中的控件
holder.tv_name = (TextView) convertView
.findViewById(R.id.tv_name);
holder.tv_phone = (TextView) convertView
.findViewById(R.id.tv_phone);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
// 3,给控件赋值
holder.tv_name.setText(getItem(position).get("name"));
holder.tv_phone.setText(getItem(position).get("phone"));
return convertView;
}
}
class Holder {
public TextView tv_name;
public TextView tv_phone;
}
}
ListView 显示布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lv_contact_list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
item 布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical" >
<TextView
android:text="联系人名称"
android:id="@+id/tv_name"
android:textSize="18sp"
android:textColor="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="联系人电话号码"
android:id="@+id/tv_phone"
android:textSize="18sp"
android:textColor="@color/grey"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
注意:
获取联系人需要申请权限
<!-- 读取联系人的权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
至此,已经可以获取并显示联系人信息。
3.获取短信内容的方法
短信内容数据也是Android
系统提供的,获取方法如下:
- 获取方法如下
package com.programandroid.ContentProvider;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.widget.CursorAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
import com.programandroid.MainActivity;
import com.programandroid.R;
/*
* MmsListActivity.java
*
* Created on: 2017-9-13
* Author: wangjie
*
* Welcome attention to weixin public number get more info
*
* WeiXin Public Number : ProgramAndroid
* 微信公众号 :程序员Android
*
*/
public class MmsListActivity extends Activity {
private ContentResolver resolver;
private ListView listView;
private static final String SMS_URI = "content://sms";
private Cursor cursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mms_list);
listView = (ListView) findViewById(R.id.lv_mms);
resolver = getContentResolver();
}
public void GetMMSBtn(View view) {
// 插入数据
ContentValues values = new ContentValues();
values.put("address", "136259");
values.put("body", "测试数据中。。。。。");
resolver.insert(Uri.parse(SMS_URI), values);
// 查询数据方法
cursor = resolver.query(Uri.parse(SMS_URI), null, null, null, null);
// 将数据显示到ListView中
listView.setAdapter(new MyAdapter(MmsListActivity.this, cursor,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER));
}
@Override
protected void onDestroy() {
super.onDestroy();
if (cursor != null) {
// 关闭cursor
// cursor.close();
}
}
class MyAdapter extends CursorAdapter {
public MyAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
// 创建一个视图,引入listview要展示的子视图
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return getLayoutInflater().inflate(R.layout.list_item_mms, null);
}
// 绑定数据的方法
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tvNumber = (TextView) view.findViewById(R.id.tv_number);
TextView tvContent = (TextView) view.findViewById(R.id.tv_content);
TextView tvState = (TextView) view.findViewById(R.id.tv_state);
TextView tvDate = (TextView) view.findViewById(R.id.tv_date);
TextView tvId = (TextView) view.findViewById(R.id.tv_id);
TextView tvRead = (TextView) view.findViewById(R.id.tv_read);
String number = cursor.getString(cursor.getColumnIndex("address"));
String body = cursor.getString(cursor.getColumnIndex("body"));
String date = cursor.getString(cursor.getColumnIndex("date"));
int read = cursor.getInt(cursor.getColumnIndex("read"));
int id = cursor.getInt(cursor.getColumnIndex("_id"));
int type = cursor.getInt(cursor.getColumnIndex("type"));
if (read == 0) {
tvRead.setText("短信状态:未读");
} else {
tvRead.setText("短信状态:已读");
}
tvNumber.setText("手机号:" + number);
tvContent.setText("短信内容:" + body);
tvDate.setText("接收短信时间:" + date);
tvId.setText("短信Id:" + id);
if (type == 1) {
tvState.setText("短信状态:已接收");
} else {
tvState.setText("短信状态:已发送");
}
}
}
}
ListView 布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lv_mms"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
item 布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_read"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
</LinearLayout>
4. ContentResolver 内容解析者
ContentResolver
主要是通过URI
调用getContentResolver()
获取ContentProvider
提供的数据接口,进而进行增删改查等操作。
// 查询
Cursor cursor = getContentResolver().query(Uri.parse(uri), null, null, null, null);
// 插入数据到指定 URI 中
getContentResolver().insert(Uri.parse(uri), ContentValues);
5.ContentObserver 内容观察者
ContentObserver
内容观察者通过指定URI
监听ContentProvider
数据是否改变。
自定义 ContentObserver 内容观察者
1.注册ContentObserver 内容观察者 registerContentObserver
/**
* 监听ContentProvider数据库变化
*/
private void ContentObserverDatabase() {
// [1]注册内容观察者
Uri uri = Uri.parse("content://ProgramAndroid/person");
// false 观察的uri 必须是一个确切的uri 如果是true
getContentResolver().registerContentObserver(uri, true,
new CustomContentObserver(new Handler()));
}
2.继承 ContentObserver 实现 onChange方法
package com.programandroid.ContentProvider;
import android.database.ContentObserver;
import android.os.Handler;
/*
* CustomContentObserver.java
*
* Created on: 2017-9-13
* Author: wangjie
*
* Welcome attention to weixin public number get more info
*
* WeiXin Public Number : ProgramAndroid
* 微信公众号 :程序员Android
*
*/
public class CustomContentObserver extends ContentObserver {
/**
* @param handler
*/
public CustomContentObserver(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}
// 当我们观察的uri发生改变的时候调用
@Override
public void onChange(boolean selfChange) {
System.out.println(" 数据库被操作了 ");
super.onChange(selfChange);
}
}
至此自定义内容观察者已经实现完成
调用ContentObserver 监听短信数据改变
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]注册一个内容观察者
Uri uri = Uri.parse("content://sms/");
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
}
private class MyContentObserver extends ContentObserver{
public MyContentObserver(Handler handler) {
super(handler);
}
//当观察的内容发生改变的时候调用
@Override
public void onChange(boolean selfChange) {
System.out.println(" 短信的数据库发生了改变");
super.onChange(selfChange);
}
}
6. ContentProvider ContentResolver ContentObserver 三者关系
- 三者关系图如下
至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!
ContentProvider 使用详解的更多相关文章
- Android中内容提供者ContentProvider的详解
1.什么是ContentProvider 首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少. ContentProvider为不 ...
- ContentProvider数据访问详解
ContentProvider数据访问详解 Android官方指出的数据存储方式总共有五种:Shared Preferences.网络存储.文件存储.外储存储.SQLite,这些存储方式一般都只是在一 ...
- Android开发数据存储之ContentProvider详解
转载:十二.ContentProvider和Uri详解 一.使用ContentProvider(内容提供者)共享数据 ContentProvider在android中的作用是对外共享数据,也就是说你可 ...
- 【转】android四大组件--ContentProvider详解
一.相关ContentProvider概念解析: 1.ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences. ...
- Android ContentProvider 基本原理和使用详解
ContentProvider(内容提供者)是 Android 的四大组件之一,管理 Android 以结构化方式存放的数据,以相对安全的方式封装数据(表)并且提供简易的处理机制和统一的访问接口供其他 ...
- Android proguard 详解
本文转载于:http://blog.csdn.net/banketree/article/details/41928175 简介 Java代码是非常容易反编译的.为了很好的保护Java源代码,我们往往 ...
- [转]AndroidManifest.xml文件详解
转自:http://www.cnblogs.com/greatverve/archive/2012/05/08/AndroidManifest-xml.html AndroidManifest.xml ...
- Android笔记——四大组件详解与总结
android四大组件分别为activity.service.content provider.broadcast receiver. ------------------------------- ...
- StrictMode使用详解
http://hb.qq.com/a/20110914/000054.htm http://www.android100.org/html/201204/25/1097.html http://www ...
随机推荐
- filebeat直连elasticsearch利用pipeline提取message中的字段
这里使用filebeat直连elasticsearch的形式完成数据传输,由于没有logstash,所有对于原始数据的过滤略显尴尬(logstash的filter非常强大). 但是由于业务需求,还是需 ...
- web前端css(一)
一 css的引入方式: 1) 行内样式: <p style=”color: green”>我是一个段落</p> 2) 内接样式: <style ty ...
- ~~小练习:python的简易购物车~~
进击のpython 1,用户先给自己的账户充钱:比如先充3000元. 2,有如下的一个格式: goods = [{"name": "电脑", "pri ...
- .net持续集成cake篇之cake任务依赖、自定义配置荐及环境变量读取
系列目录 新建一个构建任务及任务依赖关系设置 上节我们通过新建一个HelloWorld示例讲解了如何编写build.cake以及如何下载build.ps1启动文件以及如何运行.实际项目中,我们使用最多 ...
- [笨方法学python]习题51自动化测试笔记
习题51 本节自动化测试部分看不大懂,自己每步都打印出来,帮助理解.(代码标红部分为自己加入调试为打印变量值所用) tests/tools.py from nose.tools import * im ...
- .net学习笔记之访问数据库
.net中访问数据库的两中方法 第一种是通过SqlHelper帮助类来访问数据库, 使用的是ADO.net技术. using System.Data; using System.Data.SqlCli ...
- exgcd、二元一次不定方程学习笔记
(不会LATEX,只好用Word) ( QwQ数论好难) 再补充一点,单次询问a,b求逆元的题可以直接化简然后套用exgcd求解. 例题:https://www.luogu.org/problemne ...
- NOIP2018普及T2暨洛谷P5016 龙虎斗
题目链接:https://www.luogu.org/problemnew/show/P5016 分析: 这是一道模拟题.看到题目,我们首先要把它细致的读明白,模拟题特别考察细节,往往会有想不到的坑点 ...
- css 图片裁剪显示
用object-fit:cover object-fit属性详解 object-fit:CSS 属性指定替换元素的内容应该如何适应到其使用的高度和宽度确定的框. object-fit:fill 被替换 ...
- web页面保存图片到本地
web页生成分享海报功能踩坑经验 https://blog.csdn.net/candy_home/article/details/78424642 https://www.jianshu.com/p ...