参考:Android开发基础之内容提容者ContentProvider

Android四大组件 内容提供者是四大组件之一,还记得Android的四大组件吗?

前面我们学习了三大组件了,对吧!

其中有:

Activity

服务Service

广播接收者

什么是内容提供者?

我们在学习一门新的东西的时候,我们都需要知道,是为什么,有什么用,怎么用!这是最基础的,当你会用以后,如果还有好奇心,可以去究其原理!

这篇文章需要的基础知识有,请看往回跟数据库相关的文章:

https://www.sunofbeach.net/c/1179993764073156608

相关的视频下载:

链接:https://pan.baidu.com/s/1qZ30FSS 密码:m2dg

后面的课程,我们会使用到系统上层应用的源码:

上面这个连接可以下载,后面我们需要分析系统的原码,才可以实现一些功能,大家先下载下来吧!

好,回到我们的内容提供者上面:ContentProvider

内容提供者,我们从字面上认识,就是一个提供内容的东西!

这东西常用吗?用得比较少,我做了四年android开发,只有一个项目用上了,就是蓝牙电话。为什么会用上呢?因为需要拿到联系人的数据!

内容提供者,就是向第三方暴露自己的数据库的!目前来说,只有google的短信/电话是这么做的,其他应用基本上不会这么做!所以呢,使用场景也少了!比如说微信/支付宝,在第一次使用的时候会询问你是否同意让它读取你的联系人/通讯录,就是通过内容提供者来读取的。

但是,这文章学是会详细地写给大家,还是值得一看的文章!

创建数据库

我们在学习之前,都是以Hello world的方式来学习!先是一个入门的例子!

现在,我们要做这样一件事情,在应用A里有数据库,和内容提供者。应用B通过内容提供者操作A的数据库。

数据库的创建:

比如说,我们有一个学生的成绩表,字段有:id、姓名、语文、英语、数学

首先,我们编写一个数据库的帮助类,StudentScoreDBHelper.java,继承自SQLiteOpenHelper

package com.sunofbeaches.providerdemo.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log; /**
* Created by TrillGates on 18/7/5.
* God bless my code!
*/
public class StudentScoreDBHelper extends SQLiteOpenHelper {
//数据库名
private static final String DB_NAME = "student.db";
//数据库版本,如果数据库相关的不太懂,同学们可以去看数据库相关的视频课程
private static final int DB_VERSION = 1;
//表名,一般是前缀+表名
public static final String TABLE_NAME = "sob_score";
//字段,一般这么设计,我们这里只做演示
public static final String ID = "_id";
public static final String NAME = "name";
public static final String SCORE_CHINESE = "scorechinese";
public static final String SCORE_MATH = "scoremath";
public static final String SCORE_ENGLISH = "scoreenglish";
//数据库创建语句
private static final String CREATE_TABLE_SQL = "create table " + TABLE_NAME +
" (" + ID + " integer primary key autoincrement, " +
NAME + " varchar(32), " +
SCORE_CHINESE + " integer, " +
SCORE_MATH + " integer, " +
SCORE_ENGLISH + " integer" + " )"; private static final String TAG = "StudentScoreDBHelper"; public StudentScoreDBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
} @Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
Log.d(TAG, "create table...");
//创建数据库
sqLiteDatabase.execSQL(CREATE_TABLE_SQL);
} @Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//升级数据库,具体的内容同学们去学习数据库相关的课程吧,前面有的
}
}

还在DAO呢!我们暂时提供增删改查的接口,也就是CRUD

package com.sunofbeaches.providerdemo.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import com.sunofbeaches.providerdemo.domain.StudentScore; /**
* Created by TrillGates on 18/7/6.
* God bless my code!
*/
public class StudentScoreDAO implements IStudentScoreDao { private final Context mContext;
private final StudentScoreDBHelper mStudentScoreDBHelper; private StudentScoreDAO(Context context) {
this.mContext = context;
mStudentScoreDBHelper = new StudentScoreDBHelper(context);
} private static StudentScoreDAO sInstance = null; /**
* 获取实例对象
*
* @param context 上下文
* @return 返回学生成绩的DAO
*/
public static IStudentScoreDao getInstance(Context context) {
if (sInstance == null) {
synchronized (StudentScoreDAO.class) {
sInstance = new StudentScoreDAO(context);
}
}
return sInstance;
} @Override
public void addStudentScore(String studentName, int chinese, int math, int english) {
SQLiteDatabase writableDatabase = mStudentScoreDBHelper.getWritableDatabase();
try {
//
ContentValues values = new ContentValues();
values.put(StudentScoreDBHelper.NAME, studentName);
values.put(StudentScoreDBHelper.SCORE_CHINESE, chinese);
values.put(StudentScoreDBHelper.SCORE_MATH, math);
values.put(StudentScoreDBHelper.SCORE_ENGLISH, english);
//
writableDatabase.beginTransaction();
writableDatabase.insert(StudentScoreDBHelper.TABLE_NAME, null, values);
writableDatabase.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
writableDatabase.endTransaction();
writableDatabase.close();
}
} @Override
public StudentScore getStudentScoreByName(String name) {
SQLiteDatabase readableDatabase = mStudentScoreDBHelper.getReadableDatabase();
try {
Cursor query = readableDatabase.query(StudentScoreDBHelper.TABLE_NAME,
new String[]{StudentScoreDBHelper.NAME},
null,
new String[]{name},
null,
null,
null);
//
readableDatabase.beginTransaction();
StudentScore studentScore = new StudentScore();
if (query.moveToNext()) {
String studentName = query.getString(query.getColumnIndex(StudentScoreDBHelper.NAME));
int chinese = query.getInt(query.getColumnIndex(StudentScoreDBHelper.SCORE_CHINESE));
int math = query.getInt(query.getColumnIndex(StudentScoreDBHelper.SCORE_MATH));
int english = query.getInt(query.getColumnIndex(StudentScoreDBHelper.SCORE_ENGLISH));
studentScore.name = studentName;
studentScore.scorechinese = chinese;
studentScore.scoreenglish = english;
studentScore.scoremath = math;
}
//
readableDatabase.setTransactionSuccessful();
return studentScore;
} catch (Exception e) {
e.printStackTrace();
} finally {
readableDatabase.endTransaction();
readableDatabase.close();
}
return null;
} @Override
public int deleteStudentByName(String name) {
SQLiteDatabase readableDatabase = mStudentScoreDBHelper.getReadableDatabase();
try {
readableDatabase.beginTransaction();
int delete = readableDatabase.delete(StudentScoreDBHelper.TABLE_NAME,
"where " + StudentScoreDBHelper.NAME + " = ?",
new String[]{name});
readableDatabase.setTransactionSuccessful();
return delete;
} catch (Exception e) {
e.printStackTrace();
} finally {
readableDatabase.endTransaction();
readableDatabase.close();
}
return 0;
} @Override
public int modifyStudentScore(String name, int chinese, int math, int english) {
SQLiteDatabase writableDatabase = mStudentScoreDBHelper.getWritableDatabase();
try {
//
ContentValues values = new ContentValues();
values.put(StudentScoreDBHelper.SCORE_ENGLISH, english);
values.put(StudentScoreDBHelper.SCORE_MATH, math);
values.put(StudentScoreDBHelper.SCORE_CHINESE, chinese);
//
writableDatabase.beginTransaction();
int update = writableDatabase.update(StudentScoreDBHelper.TABLE_NAME, values,
"where " + StudentScoreDBHelper.TABLE_NAME + " = ?", new String[]{name});
writableDatabase.setTransactionSuccessful();
return update;
} catch (Exception e) {
e.printStackTrace();
} finally {
writableDatabase.endTransaction();
writableDatabase.close();
}
return 0;
}
}

测试一下吧,我们添加数据进去:

插入10条记录:

只有几个人及格,太让我失望了!

好啦,到此为止,我们的数据库部分就写完了,接下来我们到重点内容了,内容提供者!

为什么要使用内容提供者呢?

上面我们已经创建了数据库了,我们可以看出,数据库的权限是:

熟悉Linux的同学都知道,Linux的权限是这样分的,(-rw)前面个是用户的权限,(-rw)中间三个是同一个用户组的权限,(—)后面三个是其他用户的权限。

在android里面,每一个应用可以看做是一个应用,那么我们可以认为,其他应用是没办法访问到这个数据库的。有些情况下,需要访问别人的数据库,这个时候就需要我们的内容提供者了!

比如说今日头条需要访问淘宝的内容,根据淘宝的用户访问习惯来给使用今日头条的用户推荐定向广告,比如说我们开发一个蓝牙电话,需要向手机的联系人这个应用拿到手机的所有联系人,etc.

内容提供者,就是给别人暴露我们本应用里的数据库的,至于想暴露那些数据库,怎么样的其他应用才能访问,就看后面的内容吧!

内容提供者

创建内容提者的步骤:

第一步:编写一个类 继承自内容提供者(ContentProvider)这个例子的目的是让大家知道这个内容提供者的工作流程就够了!实际的使用我们后面再详细说明吧!

四大组件都是要继承自XXX的,总结到了吗?为什么呢?因为它要由系统去创建,生命周期由系统去管理呀!

package com.sunofbeaches.providerdemo.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; /**
* Created by TrillGates on 18/7/15.
* God bless my code!
*/
public class StudentScoreProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
} @Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
return null;
} @Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
} @Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
return null;
} @Override
public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
return 0;
} @Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
return 0;
}
}

第二步:注册一下呗!

我们四大组件都要注册,这个知道吧!所以我们需要在AndroidManifest.xml里进行注册!

我们可以发现,有两个参数必填的哦!name我们知道,是这填写空上类的全路径名称。

authorities是什么呢?其实就是令牌,口令,暗号!对得上,匹配得了的,才有权限来操作数据库。

一般来说,这个我们填写报名就OK了!如下:

provider最好加多一项:

android:exported=”true”

我们内容提供者的代码怎么写呢?

我们先暂时写一个查询的代码:

package com.sunofbeaches.providerdemo.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri; import com.sunofbeaches.providerdemo.db.StudentScoreDBHelper; /**
* Created by TrillGates on 18/7/15.
* God bless my code!
*/
public class StudentScoreProvider extends ContentProvider { StudentScoreDBHelper mStudentScoreDBHelper;
//定义一个Uri匹配器,参数表示不匹配的时候返回什么值,这里返回的是-1,也就是说-1表示不匹配
private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); //这个表示匹配
private static final int CODE_MATCH = 1; static {
//添加匹配规则,前面是authority,这个其实就是我们在配置文件里配置的那个认证字符串
//第二个参数是path,一般表示表名
//第三个表示the code that is returned when a URI is matched,也就是说规则匹配则会返回后面那个code
// 否则返回前面我们指定的默认 UriMatcher.NO_MATCH
mUriMatcher.addURI("com.sunofbeaches.providerdemo","sob_score",CODE_MATCH);
} @Override
public boolean onCreate() {
//注意,这里getContext()
//Only available once
// * {@link #onCreate} has been called
//里面的注释是:只有当onCreate方法被调用以后,getContext这个方法才可用。
mStudentScoreDBHelper = new StudentScoreDBHelper(getContext());
return false;
} @Override
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
int match = mUriMatcher.match(uri);
if (match==CODE_MATCH) {
SQLiteDatabase readableDatabase = mStudentScoreDBHelper.getReadableDatabase();
return readableDatabase.query(StudentScoreDBHelper.TABLE_NAME, strings, s, strings1, s1, null, null);
}else{
throw new IllegalArgumentException("Uri not matching.");
}
} @Override
public String getType( Uri uri) {
return null;
} @Override
public Uri insert( Uri uri, ContentValues contentValues) {
return null;
} @Override
public int delete( Uri uri, String s, String[] strings) {
return 0;
} @Override
public int update( Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0;
}
}

相关的细节已经在注释里了!

接下来,我们要写另外一个应用,通过内容提供者的方式来获取到当前应用的数据了。

package com.sunofbeaches.providerdemoteacher;

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void getScore(View view) {
ContentResolver contentResolver = this.getContentResolver();
Uri uri = Uri.parse("content://com.sunofbeaches.providerdemo/sob_score");
Cursor cursor = contentResolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
Log.d(TAG, "id is -- > " + cursor.getInt(0));
Log.d(TAG, "name is -- > " + cursor.getString(1));
Log.d(TAG, "Chinese is -- > " + cursor.getInt(2));
Log.d(TAG, "Math is -- > " + cursor.getInt(3));
Log.d(TAG, "English is -- > " + cursor.getInt(4));
}
cursor.close();
}
}

执行结果怎么样的呢?

OK,到这里的话,我们成功地读取到了另外一个应用的数据库内容了。

我们稍微总结一下:

首先是有一个数据库,但是这个数据库是别人家的呀,但是这个别人家的数据库有一个内容提供者呢!

我们只要知道对应的认证就可以读取到数据了!

所以,接下来我们就要仿今日头条,仿腾讯QQ,微信这些应用获取到手机号码,也就是通讯录的内容。

获取到通讯录的电话号码

有些时候,我们的应用为了推广,所以希望把用户的通讯录手机号码拿到,自动向他推荐好友。

这个时候,我们就可以通过内容提供者来获取到手机通讯录的联系人了。

以上的内容保存在哪个数据库里呢?

我直接帖出来吧:

/data/data/com.android.providers.contacts/databases/contacts2.db

我们把这个数据库导出来以后,用一些工具,或者用AS自带的工具就可以查看数据库了。

其实重要的表有三张:raw_contacts,data,mimetypes.

row_contacts主要是记录联系人的id,data记录数据,各种数据,包括邮箱呀,联系人名称呀,号码之类的,而mimeytypes用于记录data里的数据类型。因为data里同一个id同一个字段会有多条数据,比如说,id=1的联系人,data1字段,可能有联系人名称,联系人号码,邮箱等等,但是一条记录里会有mimetype的id,这样子就可以知道这条记录是联系人名称还是联系人号码了,具体请看下面的文章吧.

代码步骤如下:

1、获取到内容提供者:

通过context来获取到,也就是

ContentResolver contentResolver = getContentResolver();

2、我们需要Uri,但是不知道是什么,对吧!

但是我们知道,android是开源的呢!所以我们可以去看上层应用的源码:

Android上层应用源码下载

下载下来以后,我们去查看一下源码

解压源码以后,找到:

packages/providers/ContactsProvider/src/com/android/providers/contacts

下面的ContactsProvider2.java这个类,你问我怎么知道是这个类的呢?当然是看AndroidManifest.xml这个配置文件啦,你看一下就知道在哪里了:

接着我们去看看代码:

    /** The authority for the contacts provider */
public static final String AUTHORITY = "com.android.contacts";

但是我们的URI,是不是要加上协议呢,也就是前面那部分:content://

在ContactsContract这个类里,我们看到有一个AUTHORITY_URI常量,也就是说,这个可以用,前面部分的:content://com.android.contacts部分就有了!但是我们还要path的内容呀!

前面我们说了,一般来说,path指的是表名,我们的思路是查询到联系人的id,再通过id去查询号码。

那么我们的URI就有了:AUTHORITY_URI+”/raw_contacts”

代码如下:

package com.sunofbeaches.providerdemoteacher;

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View; import static android.provider.ContactsContract.AUTHORITY_URI; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void getScore(View view) {
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(Uri.parse(AUTHORITY_URI+"/raw_contacts"),//uri
new String[]{"contact_id"},//要查的内容
null,//条件
null,//条件参数
null,//排序
null);
while (cursor.moveToNext()) {
Log.d(TAG, "contact_id -- > " + cursor.getInt(0));
}
}
}

运行结果:

contact_id -- > 1
contact_id -- > 2
contact_id -- > 3
contact_id -- > 4

有了id,以后,我们再去查询对应的号码之类的数据

package com.sunofbeaches.providerdemoteacher;

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View; import java.util.ArrayList;
import java.util.List; import static android.provider.ContactsContract.AUTHORITY_URI; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void getScore(View view) {
List<Integer> contactIds = new ArrayList<>();
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(Uri.parse(AUTHORITY_URI + "/raw_contacts"),//uri
new String[]{"contact_id"},//要查的内容
null,//条件
null,//条件参数
null,//排序
null);
while (cursor.moveToNext()) {
Log.d(TAG, "contact_id -- > " + cursor.getInt(0));
contactIds.add(cursor.getInt(0));
}
cursor.close(); for (Integer contactId : contactIds) {
Cursor dataCursor = contentResolver.query(Uri.parse(AUTHORITY_URI + "/data"),
new String[]{"mimetype", "data1", "raw_contact_id"},
"raw_contact_id=?",
new String[]{contactId + ""},
null);
while (dataCursor.moveToNext()) {
Log.d(TAG, "contact info is -- > " +
"mimetype -- > " + dataCursor.getString(dataCursor.getColumnIndex("mimetype")) +
"\ndata1 -- > " + dataCursor.getString(dataCursor.getColumnIndex("data1")) +
"\nraw_contact_id -- > " + dataCursor.getString(dataCursor.getColumnIndex("raw_contact_id")));
}
Log.d(TAG, "\n|-------------------------------|");
dataCursor.close();
} }
}

运行结果如下:

09-16 01:13:22.814 6309-6309/com.sunofbeaches.providerdemoteacher D/MainActivity: contact_id -- > 1
contact_id -- > 2
contact_id -- > 3
contact_id -- > 4
09-16 01:13:22.818 6309-6309/com.sunofbeaches.providerdemoteacher D/MainActivity: contact info is -- > mimetype -- > vnd.android.cursor.item/phone_v2
data1 -- > 1 234-567-8901
raw_contact_id -- > 1
contact info is -- > mimetype -- > vnd.android.cursor.item/name
data1 -- > Zhangsan
raw_contact_id -- > 1
|-------------------------------|
09-16 01:13:22.823 6309-6309/com.sunofbeaches.providerdemoteacher D/MainActivity: contact info is -- > mimetype -- > vnd.android.cursor.item/phone_v2
data1 -- > 1180-974-6573
raw_contact_id -- > 2
contact info is -- > mimetype -- > vnd.android.cursor.item/name
data1 -- > Lisi
raw_contact_id -- > 2
|-------------------------------|
09-16 01:13:22.826 6309-6309/com.sunofbeaches.providerdemoteacher D/MainActivity: contact info is -- > mimetype -- > vnd.android.cursor.item/phone_v2
data1 -- > 668-9
raw_contact_id -- > 3
contact info is -- > mimetype -- > vnd.android.cursor.item/name
data1 -- > HuangDachui
raw_contact_id -- > 3
|-------------------------------|
09-16 01:13:22.829 6309-6309/com.sunofbeaches.providerdemoteacher D/MainActivity: contact info is -- > mimetype -- > vnd.android.cursor.item/phone_v2
data1 -- > 1 353-232-3332
raw_contact_id -- > 4
contact info is -- > mimetype -- > vnd.android.cursor.item/name
data1 -- > Chenzao
raw_contact_id -- > 4
|-------------------------------|

这样子,我们就可以获取到了联系人的数据了。

接着我们整理一下,就可以得到联系人名称和号码了,如果以后你还需要邮箱地址的话,获取方式也是一样的。

package com.sunofbeaches.providerdemoteacher;

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View; import java.util.ArrayList;
import java.util.List; import static android.provider.ContactsContract.AUTHORITY_URI; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} class ContactInfo {
public int id;
public String name;
public String phoneNum; @Override
public String toString() {
return "ContactInfo{" +
"id=" + id +
", name='" + name + '\'' +
", phoneNum='" + phoneNum + '\'' +
'}';
}
} public void getScore(View view) {
List<ContactInfo> contactInfos = new ArrayList<>();
List<Integer> contactIds = new ArrayList<>();
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(Uri.parse(AUTHORITY_URI + "/raw_contacts"),//uri
new String[]{"contact_id"},//要查的内容
null,//条件
null,//条件参数
null,//排序
null);
while (cursor.moveToNext()) {
//Log.d(TAG, "contact_id -- > " + cursor.getInt(0));
contactIds.add(cursor.getInt(0));
}
cursor.close(); for (Integer contactId : contactIds) {
ContactInfo contactInfo = new ContactInfo();
contactInfo.id = contactId;
Cursor dataCursor = contentResolver.query(Uri.parse(AUTHORITY_URI + "/data"),
new String[]{"mimetype", "data1", "raw_contact_id"},
"raw_contact_id=?",
new String[]{contactId + ""},
null);
while (dataCursor.moveToNext()) {
// Log.d(TAG, "contact info is -- > " +
// "mimetype -- > " + dataCursor.getString(dataCursor.getColumnIndex("mimetype")) +
// "\ndata1 -- > " + dataCursor.getString(dataCursor.getColumnIndex("data1")) +
// "\nraw_contact_id -- > " + dataCursor.getString(dataCursor.getColumnIndex("raw_contact_id"))); String mimetype = dataCursor.getString(dataCursor.getColumnIndex("mimetype"));
if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
String phoneNum = dataCursor.getString(dataCursor.getColumnIndex("data1"));
contactInfo.phoneNum = phoneNum;
} if ("vnd.android.cursor.item/name".equals(mimetype)) {
String name = dataCursor.getString(dataCursor.getColumnIndex("data1"));
contactInfo.name = name;
} }
//Log.d(TAG, "\n|-------------------------------|");
dataCursor.close();
contactInfos.add(contactInfo);
} //查询完成:输出结果
for (ContactInfo contactInfo : contactInfos) {
Log.d(TAG, "contactInfo -- > " + contactInfo);
} }
}

输出结果:

contactInfo -- > ContactInfo{id=1, name='Zhangsan', phoneNum='1 234-567-8901'}
contactInfo -- > ContactInfo{id=2, name='Lisi', phoneNum='1180-974-6573'}
contactInfo -- > ContactInfo{id=3, name='HuangDachui', phoneNum='668-9'}
contactInfo -- > ContactInfo{id=4, name='Chenzao', phoneNum='1 353-232-3332'}

到此,我们就拿到了手机联系人的地址了。不过要注意的是,这需要权限呢:

<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

读取联系人的权限,有了这些知识,是不是可以去做手机联系人备份了呢?

我们获取到了联系人,接下来,是不是要操作短信呢?

短信相关的内容提供者!

跟前面一样,我们首先要知道,短信是存在哪个数据库里的,存在什么表里的。这样子我们都知道怎么样去操作它。

/data/data/com.android.providers.telephony/databases/mmssms.db

在这个路径下就可以找到信息相关的内容了

但是我们没有短信内容,就创建一些吧

我们把数据库导出来

数据库是怎么样的呢?

address,目的发送的号码,比如说我要发送给

data,也就是时间

read表示的是是否已经读过,1表示已经读了,0表示未读

body表示内容

当然啦,还有其他的字段,比如说表示状态的,这个大家可以自己去看看啦!

接下来,我们就要写代码了,模拟给自己的手机发送一条短信。

首先,我们知道uri吧,怎么办?看代码呗

packages/providers/TelephonyProvider

先看清单文件

这一个Provider就是短信内容提供者的类了,同学们应该也看到了,需要读写的权限,需要在我们的清单文件里声明短信的读写权限

我们尝试一下读取短信的内容:


public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void sendMsm(View view) { //获取到内容提供者解析器
ContentResolver contentResolver = this.getContentResolver();
Uri uri = Uri.parse("content://sms/");
Cursor query = contentResolver.query(uri, null, null, null, null);
while (query.moveToNext()) {
String body = query.getString(query.getColumnIndex("body"));
Log.d(TAG, "body -- > " + body);
}
}
}

运行结果:

09-17 14:39:43.601 3334-3334/? D/MainActivity: body -- > Your phone has been lost
09-17 14:39:43.601 3334-3334/? D/MainActivity: body -- > 这是一条来自模拟器的短信

OK,到这里就可以获取到了 短信的内容了。

这样是不是有一个应用场景,监听到有短信来的广播,然后去读取短信,自动获取到验证码,自动填充到你的应用里呢。

总结一下吧

我们当我们需要暴露数据给第三方使用时,就需要知道前面的内容提供者怎么写了。

如果是读取别人的内容提供者内容,就需要后面的知识了。

学习内容提供者的话,顺便也要把数据库的知识巩固一下。

内容提供者的使用场景比较少,能列举出来就那么几个了。我只有在蓝牙电话上使用过内容提供者,当然啦,在我们的平时开发中,如果做社交软件的话,也需要获取到用户的联系人列表

然后保存到后台去,向用户推荐对应的好友用户。

四大组件之内容提容者ContentProvider的更多相关文章

  1. 【Android】安卓四大组件之内容提供者

    [Android]安卓四大组件之内容提供者 1.关于内容提供者 1.1 什么是内容提供者 内容提供者就是contentProvider,作用有如下: 给多个应用提供数据 类似一个接口 可以和多个应用分 ...

  2. Android四大组件应用系列5——使用AIDL实现跨进程调用Service

    一.问题描述 Android应用程序的四大组件中Activity.BroadcastReceiver.ContentProvider.Service都可以进行跨进程.在上一篇我们通过ContentPr ...

  3. Android四大组件之一:ContentProvider(内容提供者)

    Android中还提供了名为ContentProvider(内容提供者),可以向其他应用提供数据,但不常用,除非是同一公司开发的App,可以向不同应用提供数据.虽然为Android的四大组件之一,但用 ...

  4. 四大组件之ContentProvider

    前言 ContentProvider作为Android的四大组件之一,是属于需要掌握的基础知识,可能在我们的应用中,对于Activity和Service这两个组件用的很常见,了解的也很多,但是对Con ...

  5. 初学android:四大组件之contentprovider

    一.ContentProvider的概念ContentProvider:为存储和获取数据提供统一的接口.可以在不同的应用程序之间共享数据.Android已经为常见的一些数据提供了默认的ContentP ...

  6. Android实训案例(五)——四大组件之一ContentProvider的使用,通讯录的实现以及ListView的优化

    Android实训案例(五)--四大组件之一ContentProvider的使用,通讯录的实现 Android四大组件是啥这里就不用多说了,看图吧,他们之间通过intent通讯 我们后续也会一一的为大 ...

  7. Android 四大组件之" ContentProvider "

    前言 ContentProvider作为Android的四大组件之一,是属于需要掌握的基础知识,可能在我们的应用中,对于Activity和Service这两个组件用的很常见,了解的也很多,但是对Con ...

  8. android四大组件--ContentProvider具体解释

    一.相关ContentProvider概念解析: 1.ContentProvider简单介绍 在Android官方指出的Android的数据存储方式总共同拥有五种,各自是:Shared Prefere ...

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

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

  10. Android四大组件之——ContentProvider(一)

    Android四大组件之--ContentProvider(一) 本人邮箱:JohnTsai.Work@gmail.com,欢迎交流讨论. 欢迎转载,转载请注明网址:http://www.cnblog ...

随机推荐

  1. 小样本利器5. 半监督集各家所长:MixMatch,MixText,UDA,FixMatch

    在前面的几个章节中,我们介绍了几种基于不同半监督假设的模型优化方案,包括Mean Teacher等一致性正则约束,FGM等对抗训练,min Entropy等最小熵原则,以及Mixup等增强方案.虽然出 ...

  2. LRU 缓存

    力扣题目 146. LRU 缓存 实现 LRU 缓存需要用到哈希链表 LinkedHashMap. LinkedHashMap 是由哈希表和双链表结合而成的,它的结构如下所示. 用自带的 Linked ...

  3. yarn使用 以及和npm对比

    yarn是facebook发布的一款取代npm的包管理工具. yarn的特点: 速度超快. Yarn 缓存了每个下载过的包,所以再次使用时无需重复下载. 同时利用并行下载以最大化资源利用率,因此安装速 ...

  4. echart大坑总结~~echarts呈现的数据刷新不完全/echarts画图时tooltip不会更新

    谨以此文记录在使用echarts中遇到的各种大坑或者小坑,陆续更新加入新坑 欢迎朋友们一起提坑,我们势必绕过它们,愿我们永不再入坑~ 坑一:echarts图表重新赋值数据,图表显示会存在一部分原来的数 ...

  5. angular在服务中调用组件的某个方法,并传参给组件,(反向调用),变量改变后,强制更新视图

    需要被调用方法的组件文件 import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; ...

  6. Python3+Selenium3自动化测试-(七)

    在实际定位元素的过程中,发现有一种情况让人很是恼火,根据xpath路径定位,感觉像是没错哦,但是执行时就来一个报错信息--为什么呢? 多表单切换 例如我们登录网易邮箱时就会发现,定位登录框时,一个嵌套 ...

  7. 分布式协议与算法-Quorum NWR

    1.强一致性与最终一致性 1.1强一致性 强一致性能保证写操作完成后,任何后续访问都能读到更新后的值:强一致性可以保证从库有与主库一致的数据.如果主库突然宕机,我们仍可以保证数据完整.但如果从库宕机或 ...

  8. uni-app + .NET 7实现微信小程序订阅消息推送

    微信小程序的订阅消息是小程序的重要能力之一,为实现服务的闭环提供更优的体验.订阅消息我们应该经常见到,比如下单成功之后的服务通知,支付成功后的支付成功通知,都属于小程序的订阅消息. 本文只实现一次性订 ...

  9. NetCoreWebApi3.0-------MiniProfiler使用教程

    参考博客:ASP.NET Core WebAPI中的分析工具MiniProfiler - LamondLu - 博客园 (cnblogs.com) 注意事项: 1.不要盲目copy别人的代码 var ...

  10. springboot集成ElasticApm

    jvm参数方式: -javaagent:D:/codesoft/elastic-apm-agent-1.18.0.jar -Delastic.apm.service_name=my-applicati ...