四大组件之内容提容者ContentProvider
参考: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是开源的呢!所以我们可以去看上层应用的源码:
下载下来以后,我们去查看一下源码
解压源码以后,找到:
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的更多相关文章
- 【Android】安卓四大组件之内容提供者
[Android]安卓四大组件之内容提供者 1.关于内容提供者 1.1 什么是内容提供者 内容提供者就是contentProvider,作用有如下: 给多个应用提供数据 类似一个接口 可以和多个应用分 ...
- Android四大组件应用系列5——使用AIDL实现跨进程调用Service
一.问题描述 Android应用程序的四大组件中Activity.BroadcastReceiver.ContentProvider.Service都可以进行跨进程.在上一篇我们通过ContentPr ...
- Android四大组件之一:ContentProvider(内容提供者)
Android中还提供了名为ContentProvider(内容提供者),可以向其他应用提供数据,但不常用,除非是同一公司开发的App,可以向不同应用提供数据.虽然为Android的四大组件之一,但用 ...
- 四大组件之ContentProvider
前言 ContentProvider作为Android的四大组件之一,是属于需要掌握的基础知识,可能在我们的应用中,对于Activity和Service这两个组件用的很常见,了解的也很多,但是对Con ...
- 初学android:四大组件之contentprovider
一.ContentProvider的概念ContentProvider:为存储和获取数据提供统一的接口.可以在不同的应用程序之间共享数据.Android已经为常见的一些数据提供了默认的ContentP ...
- Android实训案例(五)——四大组件之一ContentProvider的使用,通讯录的实现以及ListView的优化
Android实训案例(五)--四大组件之一ContentProvider的使用,通讯录的实现 Android四大组件是啥这里就不用多说了,看图吧,他们之间通过intent通讯 我们后续也会一一的为大 ...
- Android 四大组件之" ContentProvider "
前言 ContentProvider作为Android的四大组件之一,是属于需要掌握的基础知识,可能在我们的应用中,对于Activity和Service这两个组件用的很常见,了解的也很多,但是对Con ...
- android四大组件--ContentProvider具体解释
一.相关ContentProvider概念解析: 1.ContentProvider简单介绍 在Android官方指出的Android的数据存储方式总共同拥有五种,各自是:Shared Prefere ...
- 【转】android四大组件--ContentProvider详解
一.相关ContentProvider概念解析: 1.ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences. ...
- Android四大组件之——ContentProvider(一)
Android四大组件之--ContentProvider(一) 本人邮箱:JohnTsai.Work@gmail.com,欢迎交流讨论. 欢迎转载,转载请注明网址:http://www.cnblog ...
随机推荐
- Kali-Linux-for-Docker
说明 基于kali官方开源的Docker镜像修改,如需使用官方固件可以前往https://hub.docker.com/r/kalilinux/kali-rolling Docker Hub http ...
- 青少年CTF-Web-Robots
题目信息 题目名称:Robots 题目描述:昨天十三年社团讲课,讲了Robots.txt的作用,小刚上课没有认真听课正在着急,你能不能帮帮忙? 题目难度:一颗星 解题过程 访问题目链接 浏览器里是空白 ...
- [深度学习] imgaug库使用笔记
imgaug是一款非常有用的python图像增强库,非常值得推荐应用于深度学习图像增强.其包含许多增强技术,支持图像分类,目标检测,语义分割,热图.关键点检测等一系列任务的图像增强.本文主要介绍img ...
- vue-element-admin 安装(node方式)
vue-element-admin node方式安装 需要的环境: git .node.js 1.git clone 项目(2选 1) // github https://github.com/Pan ...
- 《Effective C++》构造、析构、赋值运算
Item 05:了解C++默默编写并调用了哪些函数 总结:编译器可以暗自为class创建default 构造函数.copy构造函数.copy assignment操作符,以及析构函数. (这一小节比较 ...
- 【Vue3.0】关于 script setup 语法糖的用法
script setup - 简介 先来看一看官网关于 <script setup> 的介绍: 要彻底的了解 setup 语法糖,你必须先明确 setup() 这个 组合式API 官网中对 ...
- Gvim基础操作(正则表达式)-02
Gvim正则表达式 正则表达式在linux中使用非常广泛.主要是进行一些替换,在编写脚本的时候都会使用到.gvim.perl.sed.tcl中都会使用到. Gvim正则表达式的使用 搜索命令 /正则表 ...
- GPIO-CH32x系列芯片GPIO使用注意事项
一.特殊IO使用注意事项 芯片型号:CH32F203C8T6.CH32V203C8T6 特殊IO:PC13.PC14.PC15 注意事项说明: 1.PC13~PC15的IO功能受限,速度必须限制在2M ...
- 从 Cloud-Native Relational DB 看数据库设计
论文内容:Amazon Aurora: Design Considerations for HighThroughput Cloud-Native Relational Databases 里面介绍了 ...
- SpringBoot项目启动后再请求远程接口的实现方式
场景 有一个SpringBoot项目需要在启动后请求另一个远程服务拿取配置,而不是加载过程中去请求,可能会出现类没有实例化的场景,因此需要实现项目完全启动后再进行请求的场景. 解决 一般会有两种实现方 ...