极力推荐文章:欢迎收藏

Android 干货分享

阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

  1. ContentProvider
  2. 获取联系人信息的方法
  3. 获取短信内容的方法
  4. ContentResolver 内容解析者
  5. ContentObserver 内容观察者
  6. 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 使用详解的更多相关文章

  1. Android中内容提供者ContentProvider的详解

    1.什么是ContentProvider 首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少. ContentProvider为不 ...

  2. ContentProvider数据访问详解

    ContentProvider数据访问详解 Android官方指出的数据存储方式总共有五种:Shared Preferences.网络存储.文件存储.外储存储.SQLite,这些存储方式一般都只是在一 ...

  3. Android开发数据存储之ContentProvider详解

    转载:十二.ContentProvider和Uri详解 一.使用ContentProvider(内容提供者)共享数据 ContentProvider在android中的作用是对外共享数据,也就是说你可 ...

  4. 【转】android四大组件--ContentProvider详解

    一.相关ContentProvider概念解析: 1.ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences. ...

  5. Android ContentProvider 基本原理和使用详解

    ContentProvider(内容提供者)是 Android 的四大组件之一,管理 Android 以结构化方式存放的数据,以相对安全的方式封装数据(表)并且提供简易的处理机制和统一的访问接口供其他 ...

  6. Android proguard 详解

    本文转载于:http://blog.csdn.net/banketree/article/details/41928175 简介 Java代码是非常容易反编译的.为了很好的保护Java源代码,我们往往 ...

  7. [转]AndroidManifest.xml文件详解

    转自:http://www.cnblogs.com/greatverve/archive/2012/05/08/AndroidManifest-xml.html AndroidManifest.xml ...

  8. Android笔记——四大组件详解与总结

     android四大组件分别为activity.service.content provider.broadcast receiver. ------------------------------- ...

  9. StrictMode使用详解

    http://hb.qq.com/a/20110914/000054.htm http://www.android100.org/html/201204/25/1097.html http://www ...

随机推荐

  1. WebSocket API 学习笔记

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在 W ...

  2. HDU 3938:Portal(并查集+离线处理)

    http://acm.hdu.edu.cn/showproblem.php?pid=3938 Portal Problem Description   ZLGG found a magic theor ...

  3. Spring Bean 生命周期之destroy——终极信仰

    上一篇文章 Spring Bean 生命周期之我从哪里来 说明了我是谁? 和 我从哪里来? 的两大哲学问题,今天我们要讨论一下终极哲学我要到哪里去? 初始化 Spring Bean 有三种方式: @P ...

  4. MySQL数据库设计与开发规范

    目录 1. 规范背景与目的 2. 设计规范 2.1. 数据库设计 2.1.1. 库名 2.1.2. 表结构 2.1.3. 列数据类型优化 2.1.4. 索引设计 2.1.5. 分库分表.分区表 2.1 ...

  5. redis 基础数据结构实现

    参考文献 redis数据结构分析 Skip List(跳跃表)原理详解 redis 源码分析之内存布局 Redis 基础数据结构与对象 Redis设计与实现-第7章-压缩列表 在redis中构建了自己 ...

  6. 单个单选框radio 点击选中点击取消选中

    $("input:radio").click(function(){ var domName = $(this).attr('name');//获取当前单选框控件name 属性值 ...

  7. c++ 组合

    组合 题目描述 已知一个一维数组a1..n,又已知一整数m. 如能使数组a中任意几个元素之和等于m,则输出YES,反之则为NO. 输入 输入包括两行,第一行包含两个整数n m(1<=n<2 ...

  8. Apache Dubbo已不再局限于Java语言

    2017 年 9 月 7 日,在沉寂了4年之后,Dubbo 悄悄的在 GitHub 发布了 2.5.4 版本.随后又迅速发布了 2.5.5.2.5.6.2.5.7 等release.在 2017年 1 ...

  9. C语言指针学多了,你为什么会觉得晕?

    对于C语言中的指针概念,如果我告诉你,它是一个地址变量,你听了一头雾水,"地址?啥意思?"见你不理解,我说的详细点"指针变量跟其他变量一样,存储的是一个地址". ...

  10. ElasticStack学习(十):深入ElasticSearch搜索之QueryFiltering、多/单字符串的多字段查询

    一.复合查询 1.在ElasticSearch中,有Query和Filter两种不同的Context.Query Context进行了相关性算分,Filter Context不需要进行算分,同时可以利 ...