1.sqlite回顾
1、创建数据库、表结构及输入初始诗句
package com.fengray.ex074;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MyOpenHelper extends SQLiteOpenHelper {
public MyOpenHelper(@Nullable Context context) {
super(context, "Account.db", null, 1);
}
@Override
//表结构的初始化
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table info(_id integer primary key autoincrement,name varchar(20),money varchar(20))");
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"张三","5000"});
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"李四","3000"});
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
2、主activity中实现查询逻辑
package com.fengray.ex074;
import androidx.appcompat.app.AppCompatActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyOpenHelper myOpenHelper=new MyOpenHelper(getApplicationContext());
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
Cursor cursor=database.query("info",null,null,null,null,null,null);
if (cursor!=null && cursor.getCount()>0){
while (cursor.moveToNext()){
String name= cursor.getString(1);
String phone= cursor.getString(2);
Log.d("TAG", "onCreate: "+name+"-----"+phone);
}
}
}
}
打印:
2020-08-23 12:50:20.681 12711-12711/com.fengray.ex074 D/TAG: onCreate: 张三-----5000
2020-08-23 12:50:20.681 12711-12711/com.fengray.ex074 D/TAG: onCreate: 李四-----3000
2.获取模拟器目录下数据库文件的权限
仅在本机上测试有效
1、cmd进入sdk的\platform-tools目录\android-sdk-windows\platform-tools
2、运行如下命令
adb shell
generic_86:/su
generic_86:/chmod -r /data
generic_86:/chmod -r /data/data
ctrl+break
输入 adb root
至此,模拟器下的data/data的只读权限已经打开
另可参考如下文档:
https://blog.csdn.net/qq_36124194/article/details/84455423
3、cmd下进入应用的目录
cd data/data/com.fengray.ex074/databases
chmod 777 Account.db //这里给data/data/com.fengray.ex074/databases目录下的Account.db赋予全部权限
3.使用内容提供者将私有数据库内容给暴露出来
内容提供者ContentProvider将私有数据库内容给暴露出来
工作原理
内容提供者把数据进行封装后,把数据提供出来。其他应用通过内容解析者来访问
定义内容提供者。定义一个类,继承ContentProvider
4.内容提供者访问数据库实现步骤
1、定义一个内容实现者类,继承ContentProvider
2、在清单文件中配置
注意一定要增加设定exported=“true” 外调为真,低版本api默认为true,高版本默认为false,需要手动将其打开
<provider
android:exported="true"<!--android7以后要设置外调为真-->
android:authorities="com.fengray.provider"
android:name="com.fengray.ex074.AccountProvider"></provider>
3、写一个静态代码块,添加Uri规则
static {
//这个与清单文件定义的authorities字符串要一直
//第一个参数:清单文件的authorities
//第二个参数:自定义的字符串,这里与query方法设置为一致
//第三个参数,自定义的int类型匹配码
urimather.addURI("com.fengray.provider", "query",QUERYSUCCESS);
}
4、暴露你想要暴露的方法(增删改查)
5、通过内容解析者,来读取上一个应用锁暴露出来的方法
6、其他应用就可以操作数据库
两个APP,第一个ex074,第二个ex75read
第一个应用ex074目录结构
1、MyOphenher
2、AccountProvider
3、Mainactivity
1、MyOphenher
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MyOpenHelper extends SQLiteOpenHelper {
public MyOpenHelper(@Nullable Context context) {
super(context, "Account.db", null, 1);
}
@Override
//表结构的初始化
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table info(_id integer primary key autoincrement,name varchar(20),money varchar(20))");
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"张三","5000"});
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"李四","3000"});
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
2、AccountProvider
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 android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import javax.xml.xpath.XPath;
public class AccountProvider extends ContentProvider {
//定义一个urimathcher 定义路径匹配器
private static final UriMatcher urimather=new UriMatcher(UriMatcher.NO_MATCH);
private static final int QUERYSUCCESS=0;
MyOpenHelper myOpenHelper=null;
//创建一个静态代码块,添加匹配规则
static {
//这个与清单文件定义的authorities字符串要一直
//第一个参数:清单文件的authorities
//第二个参数:自定义的字符串,这里与query方法设置为一致 content://com.fengray.ex074.provider/query。这里看到是两个参数的整合
//第三个参数,自定义的int类型匹配码
urimather.addURI("com.fengray.ex074.provider", "query",QUERYSUCCESS);
}
@Override
public boolean onCreate() {
myOpenHelper=new MyOpenHelper(getContext());
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
int code=urimather.match(uri);
if (code == QUERYSUCCESS){
//说明路径匹配成功 把query方法给实现 数据库的查询方法对数据库进行查询操作必须获得的sqlitedatabase对象
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
Cursor cursor= database.query("info",projection,selection,selectionArgs, null, null, sortOrder);
return cursor;
}else{
throw new IllegalArgumentException("路径不匹配");
}
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
3、Mainactivity
import androidx.appcompat.app.AppCompatActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyOpenHelper myOpenHelper=new MyOpenHelper(getApplicationContext());
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
Cursor cursor=database.query("info",null,null,null,null,null,null);
if (cursor!=null && cursor.getCount()>0){
while (cursor.moveToNext()){
String name= cursor.getString(1);
String phone= cursor.getString(2);
//Log.d("TAG", "onCreate: "+name+"-----"+phone);
}
}
}
}
4、清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex074">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--配置内容提供者-->
<provider
android:exported="true"
android:authorities="com.fengray.ex074.provider"
android:name="com.fengray.ex074.AccountProvider" />
</application>
第二个应用:ex075reader
MainActivity类
package com.fengray.ex075read;
import androidx.appcompat.app.AppCompatActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//通过内容解析这来获取暴露的方法,直接调用即可
Uri uri=Uri.parse("content://com.fengray.ex074.provider/query");//路径和你第一的路径一样
Cursor cursor= getContentResolver().query(uri,null,null,null,null);
if (cursor!=null && cursor.getCount()>0){
while (cursor.moveToNext()){
String name= cursor.getString(1);
String phone= cursor.getString(2);
Log.d("TAG", "onCreate: "+name+"-----"+phone);
}
}
}
}
最后第二个引用打印
2020-08-24 15:58:20.058 23465-23465/com.fengray.ex075read D/TAG: onCreate: 张三-----5000
2020-08-24 15:58:20.058 23465-23465/com.fengray.ex075read D/TAG: onCreate: 李四-----3000
5.进一步完善内容提供者访问数据库实现步骤
两个APP,第一个ex074,第二个ex75read
第一个应用ex074目录结构
1、MyOphenher
2、AccountProvider
3、Mainactivity
1、MyOphenher
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MyOpenHelper extends SQLiteOpenHelper {
public MyOpenHelper(@Nullable Context context) {
super(context, "Account.db", null, 1);
}
@Override
//表结构的初始化
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table info(_id integer primary key autoincrement,name varchar(20),money varchar(20))");
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"张三","5000"});
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"李四","3000"});
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
2、AccountProvider
package com.fengray.ex074;
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 android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import javax.xml.xpath.XPath;
public class AccountProvider extends ContentProvider {
//定义一个urimathcher 定义路径匹配器
private static final UriMatcher urimather=new UriMatcher(UriMatcher.NO_MATCH);
private static final int QUERYSUCCESS=0;
private static final int INSERTSUCCESS=0;
private static final int UPDATESUCCESS=0;
private static final int DELETESUCCESS=0;
MyOpenHelper myOpenHelper=null;
//创建一个静态代码块,添加匹配规则
static {
//这个与清单文件定义的authorities字符串要一直
//第一个参数:清单文件的authorities
//第二个参数:自定义的字符串,这里与query方法设置为一致 content://com.fengray.ex074.provider/query。这里看到是两个参数的整合
//第三个参数,自定义的int类型匹配码
urimather.addURI("com.fengray.ex074.provider", "query",QUERYSUCCESS);
urimather.addURI("com.fengray.ex074.provider", "insert",INSERTSUCCESS);
urimather.addURI("com.fengray.ex074.provider", "update",UPDATESUCCESS);
urimather.addURI("com.fengray.ex074.provider", "delete",DELETESUCCESS);
}
@Override
public boolean onCreate() {
myOpenHelper=new MyOpenHelper(getContext());
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
int code=urimather.match(uri);
if (code == QUERYSUCCESS){
//说明路径匹配成功 把query方法给实现 数据库的查询方法对数据库进行查询操作必须获得的sqlitedatabase对象
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
Cursor cursor= database.query("info",projection,selection,selectionArgs, null, null, sortOrder);
return cursor;
}else{
throw new IllegalArgumentException("路径不匹配");
}
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
int code=urimather.match(uri);
if (code == INSERTSUCCESS){
//说明路径匹配成功 把query方法给实现 数据库的查询方法对数据库进行查询操作必须获得的sqlitedatabase对象
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
//返回值代表插入的行数
long insert= database.insert("info",null,values);
Uri newUri=Uri.parse("com.fengray.ex074.insert/"+insert);
return newUri;
}else{
throw new IllegalArgumentException("路径不匹配");
}
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
int match=urimather.match(uri);
if (match == DELETESUCCESS){
//说明路径匹配成功 把query方法给实现 数据库的查询方法对数据库进行查询操作必须获得的sqlitedatabase对象
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
//返回值代表删除的行数
int delete= database.delete("info",selection,selectionArgs);
return delete;
}else{
throw new IllegalArgumentException("路径不匹配");
}
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
int code=urimather.match(uri);
if (code == UPDATESUCCESS){
//说明路径匹配成功 把query方法给实现 数据库的查询方法对数据库进行查询操作必须获得的sqlitedatabase对象
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
//返回值代表更新的行数
int update= database.update("info",values,selection,selectionArgs);
return update;
}else{
throw new IllegalArgumentException("路径不匹配");
}
}
}
3、Mainactivity
import androidx.appcompat.app.AppCompatActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyOpenHelper myOpenHelper=new MyOpenHelper(getApplicationContext());
SQLiteDatabase database=myOpenHelper.getReadableDatabase();
Cursor cursor=database.query("info",null,null,null,null,null,null);
if (cursor!=null && cursor.getCount()>0){
while (cursor.moveToNext()){
String name= cursor.getString(1);
String phone= cursor.getString(2);
//Log.d("TAG", "onCreate: "+name+"-----"+phone);
}
}
}
}
4、清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex074">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--配置内容提供者-->
<provider
android:exported="true"
android:authorities="com.fengray.ex074.provider"
android:name="com.fengray.ex074.AccountProvider" />
</application>
第二个应用:ex075reader
MainActivity类
package com.fengray.ex075read;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//增操作
public void insertClick(View view){
Uri uri=Uri.parse("content://com.fengray.ex074.provider/insert");//路径和你定义的路径一样
ContentValues contentValues= new ContentValues();
//key对应表的字段,value对应值
contentValues.put("name","王二");
contentValues.put("money",6000);
Uri insert=getContentResolver().insert(uri,contentValues);
Log.d("TAG", "insertClick: "+insert);
}
//删操作
public void deleteClick(View view){
Uri uri=Uri.parse("content://com.fengray.ex074.provider/delete");//路径和你定义的路径一样
int delete=getContentResolver().delete(uri,"name=?",new String[]{"张三"});
Log.d("TAG", "deleteClick: "+delete);
}
//改操作
public void updateClick(View view){
Uri uri=Uri.parse("content://com.fengray.ex074.provider/update");//路径和你定义的路径一样
ContentValues contentValues= new ContentValues();
//key对应表的字段,value对应值
contentValues.put("money",4500);
int update=getContentResolver().update(uri,contentValues,"money=?",new String[]{"3000"});
Log.d("TAG", "updateClick: "+update+"行");
}
//查操作
public void queryClick(View view){
//通过内容解析这来获取暴露的方法,直接调用即可
Uri uri=Uri.parse("content://com.fengray.ex074.provider/query");//路径和你定义的路径一样
Cursor cursor= getContentResolver().query(uri,null,null,null,null);
if (cursor!=null && cursor.getCount()>0){
while (cursor.moveToNext()){
String name= cursor.getString(1);
String phone= cursor.getString(2);
Log.d("TAG", "onCreate: "+name+"-----"+phone);
}
}
}
}
最后第二个引用打印
2020-08-24 15:58:20.058 23465-23465/com.fengray.ex075read D/TAG: onCreate: 张三-----5000
2020-08-24 15:58:20.058 23465-23465/com.fengray.ex075read D/TAG: onCreate: 李四-----3000
6.使用内容解析者(getcontentResolve)查询短信,插入短信(未成功)
1、清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex076">
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2、MainActivity 类
package com.fengray.ex076;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.util.Xml;
import android.view.View;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import static android.os.Environment.*;
public class MainActivity extends AppCompatActivity {
private String permssionRequestCode []={Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_SMS,
Manifest.permission.READ_EXTERNAL_STORAGE};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
}
private void requestPermission(){
//动态请求各种权限
ActivityCompat.requestPermissions(this,permssionRequestCode, 0);
ActivityCompat.requestPermissions(this,permssionRequestCode, 1);
ActivityCompat.requestPermissions(this,permssionRequestCode,2);
ActivityCompat.requestPermissions(this,permssionRequestCode,3);
}
//插入信息到短信中
public void insertClick(View view){
//由于短信数据库,系统也通过内容提供者给暴露出来,所以只需要通过内容提供者去操作数据库
Uri uri=Uri.parse("content://sms/");
ContentValues values=new ContentValues();
values.put("address","18214232155");
values.put("body","dfdf ,fdsafaskf fddasf,sdfa");
values.put("date",System.currentTimeMillis());
getContentResolver().insert(uri,values);
}
//查询短信到xml文件中
public void queryClick(View view){
//获取xml序列化实例
XmlSerializer serializer= Xml.newSerializer();
//设置序列化参数
File file=new File(getExternalStorageDirectory().getPath(),"smsBackUp.xml");
try {
FileOutputStream fileOutputStream=new FileOutputStream(file);
serializer.setOutput(fileOutputStream,"utf-8");
} catch (IOException e) {
e.printStackTrace();
}
//写xml文档开头
try {
serializer.startDocument("utf-8",true);
serializer.startTag(null,"smss");
//写子节点
//由于短信数据库,系统也通过内容提供者给暴露出来,所以只需要通过内容提供者去操作数据库
Uri uri=Uri.parse("content://sms/");
Cursor cursor=getContentResolver().query(uri,new String[]{"address","date","body"},null,null,null);
while(cursor.moveToNext()){
String address=cursor.getString(0);
String date=cursor.getString(1);
String body=cursor.getString(2);
//写sms节点
serializer.startTag(null,"sms");
//写addres节点
serializer.startTag(null,"address");
serializer.text(address);
serializer.endTag(null,"address");
//写body节点
serializer.startTag(null,"body");
serializer.text(body);
serializer.endTag(null,"body");
//写date节点
serializer.startTag(null,"date");
serializer.text(date);
serializer.endTag(null,"date");
serializer.endTag(null,"sms");
}
serializer.endTag(null,"smss");
serializer.endDocument();
} catch (IOException e) {
e.printStackTrace();
}
}
}
7.读取联系人案例
实现步骤
1、先读取raw_contact表 读取contact_id字段,从而知道手机里面一共有几条联系人数据
2、再读取data表,根据row_contact_id读取 data1列和mimety_id列。
具体实现
1、清单文件设置权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
2、清单文件设置权限
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private String permssionRequestCode []={Manifest.permission.READ_CONTACTS};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, permssionRequestCode,0);
//由于联系人的数据库也是通过内容提供者暴露出来,因此直接使用内容解析者
//先查询raw_contacts表的contact_id列
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri=Uri.parse("content://com.android.contacts/data");
Cursor cursor=getContentResolver().query(uri,new String[]{"contact_id"},null,null,null);
while (cursor.moveToNext()){
String contact_id=cursor.getString(0);
//Log.d("TAG", "onCreate: "+contact_id);
//根据contact_id 去查询data表 data列和mimety_id列
Cursor dataCursor=getContentResolver().query(datauri,new String[]{"data1","mimetype"},"raw_contact_id=?",new String[]{contact_id},null);
while (dataCursor.moveToNext()){
String data1=dataCursor.getString(0);
String mimetype=dataCursor.getString(1);
if ("vnd.android.cursor.item/name".equals(mimetype)){
Log.d("TAG", "姓名: "+data1);
}else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)){
Log.d("TAG", "电话号码: "+data1);
}else if ("vnd.android.cursor.item/email_v2".equals(mimetype)){
Log.d("TAG", "邮箱: "+data1);
}
}
}
}
}
打印出联系人详细信息
2020-08-25 10:14:32.906 6764-6764/com.fengray.ex077 D/TAG: 电话号码: 1 (861) 841-5258
2020-08-25 10:14:32.907 6764-6764/com.fengray.ex077 D/TAG: 姓名: 张三
2020-08-25 10:14:32.912 6764-6764/com.fengray.ex077 D/TAG: 电话号码: 138154875675
2020-08-25 10:14:32.912 6764-6764/com.fengray.ex077 D/TAG: 姓名: 李四
2020-08-25 10:14:32.916 6764-6764/com.fengray.ex077 D/TAG: 电话号码: 1 (755) 564-5584
2020-08-25 10:14:32.916 6764-6764/com.fengray.ex077 D/TAG: 姓名: 王二
2020-08-25 10:14:32.920 6764-6764/com.fengray.ex077 D/TAG: 电话号码: 1 (586) 548-3254
2020-08-25 10:14:32.921 6764-6764/com.fengray.ex077 D/TAG: 姓名: 丁一
2020-08-25 10:14:32.927 6764-6764/com.fengray.ex077 D/TAG: 电话号码: 1 (842) 545-4554
2020-08-25 10:14:32.927 6764-6764/com.fengray.ex077 D/TAG: 姓名: 马五
8.读取联系人案例代码封装
1、创建Contact联系人模型类
package com.fengray.ex077;
public class Contact {
private String id;
private String name;
private String phone;
private String email;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
//自动生成一个toString方法
@Override
public String toString() {
return "Contacts{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
'}';
}
}
2、联系人读取工具类ReadContactUtils
package com.fengray.ex077;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class ReadContactUtils {
public static List<Contact> readContact(Context context){
List<Contact> contactLists=new ArrayList<>();
//由于联系人的数据库也是通过内容提供者暴露出来,因此直接使用内容解析者
//先查询raw_contacts表的contact_id列
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri=Uri.parse("content://com.android.contacts/data");
Cursor cursor=context.getContentResolver().query(uri,new String[]{"contact_id"},null,null,null);
while (cursor.moveToNext()){
String contact_id=cursor.getString(0);
if (contact_id!=null){
//Log.d("TAG", "onCreate: "+contact_id);
//根据contact_id 去查询data表 data列和mimetype_id列,
// 由于查询的是view_data视图,没有mimetype列,因此实际应查询mimetype列
Cursor dataCursor=context.getContentResolver().query(datauri,new String[]{"data1","mimetype"},"raw_contact_id=?",new String[]{contact_id},null);
while (dataCursor.moveToNext()){
String data1=dataCursor.getString(0);
String mimetype=dataCursor.getString(1);
//创建一个模型对象
Contact contact=new Contact();
//设置对象属性
contact.setId(contact_id);
if ("vnd.android.cursor.item/name".equals(mimetype)){
Log.d("TAG", "姓名: "+data1);
contact.setName(data1);
}else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)){
Log.d("TAG", "电话号码: "+data1);
contact.setPhone(data1);
}else if ("vnd.android.cursor.item/email_v2".equals(mimetype)){
Log.d("TAG", "邮箱: "+data1);
contact.setEmail(data1);
}
contactLists.add(contact);
}
}
}
return contactLists;
}
}
3、主activity类
package com.fengray.ex077;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private String permssionRequestCode []={Manifest.permission.READ_CONTACTS};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, permssionRequestCode,0);
List<Contact> readContacts= ReadContactUtils.readContact(getApplicationContext());
for (Contact contact:readContacts) {
Log.d("TAG", contact+"");//Contact类自定义了一个toString方法
}
}
}
打印联系人信息:
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘1’, name=‘null’, phone=‘1 (861) 841-5258’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘1’, name=‘张三’, phone=‘null’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘2’, name=‘null’, phone=‘138154875675’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘2’, name=‘李四’, phone=‘null’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘3’, name=‘null’, phone=‘1 (755) 564-5584’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘3’, name=‘王二’, phone=‘null’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘4’, name=‘null’, phone=‘1 (586) 548-3254’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘4’, name=‘丁一’, phone=‘null’, email=‘null’}
2020-08-25 11:19:10.335 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘5’, name=‘null’, phone=‘1 (842) 545-4554’, email=‘null’}
2020-08-25 11:19:10.336 8028-8028/com.fengray.ex077 D/TAG: Contacts{id=‘5’, name=‘马五’, phone=‘null’, email=‘null’}
9.联系人中插入一条数据
实现步骤
1、先往raw_contact表的contact_id列插入数列
2、同步到data表的data1列是所有联系人的数据
1、清单文件,联系人的读写权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
2、联系人模型类Contact
package com.fengray.ex077;
public class Contact {
private String id;
private String name;
private String phone;
private String email;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
//自动生成一个toString方法
@Override
public String toString() {
return "Contacts{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
'}';
}
}
3、联系人读取工具类
package com.fengray.ex077;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class ReadContactUtils {
public static List<Contact> readContact(Context context){
List<Contact> contactLists=new ArrayList<>();
//由于联系人的数据库也是通过内容提供者暴露出来,因此直接使用内容解析者
//先查询raw_contacts表的contact_id列
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri=Uri.parse("content://com.android.contacts/data");
Cursor cursor=context.getContentResolver().query(uri,new String[]{"contact_id"},null,null,null);
while (cursor.moveToNext()){
String contact_id=cursor.getString(0);
if (contact_id!=null){
//Log.d("TAG", "onCreate: "+contact_id);
//根据contact_id 去查询data表 data列和mimetype_id列,
// 由于查询的是view_data视图,没有mimetype列,因此实际应查询mimetype列
Cursor dataCursor=context.getContentResolver().query(datauri,new String[]{"data1","mimetype"},"raw_contact_id=?",new String[]{contact_id},null);
while (dataCursor.moveToNext()){
String data1=dataCursor.getString(0);
String mimetype=dataCursor.getString(1);
//创建一个模型对象
Contact contact=new Contact();
//设置对象属性
contact.setId(contact_id);
if ("vnd.android.cursor.item/name".equals(mimetype)){
//Log.d("TAG", "姓名: "+data1);
contact.setName(data1);
}else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)){
//Log.d("TAG", "电话号码: "+data1);
contact.setPhone(data1);
}else if ("vnd.android.cursor.item/email_v2".equals(mimetype)){
//Log.d("TAG", "邮箱: "+data1);
contact.setEmail(data1);
}
contactLists.add(contact);
}
}
}
return contactLists;
}
}
4、主activity类
package com.fengray.ex077;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private String permssionRequestCode []={Manifest.permission.READ_CONTACTS,Manifest.permission.WRITE_CONTACTS};
private EditText edname,edphone,edmail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, permssionRequestCode,0);
ActivityCompat.requestPermissions(this, permssionRequestCode,1);
List<Contact> readContacts= ReadContactUtils.readContact(getApplicationContext());
edname=findViewById(R.id.edname);
edphone=findViewById(R.id.edphone);
edmail=findViewById(R.id.edmail);
for (Contact contact:readContacts) {
Log.d("TAG", contact+"");//Contact类自定义了一个toString方法
}
}
//点击插入联系人
public void insertClick(View view){
//获取数据
String name=edname.getText().toString().trim();
String phone=edphone.getText().toString().trim();
String email=edmail.getText().toString().trim();
//定义uri
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri=Uri.parse("content://com.android.contacts/data");
//查询联系人数据库有几条记录
Cursor cursor=getContentResolver().query(uri,null,null,null,null);
int count=cursor.getCount();
//把数据插入到联系人数据库 ,由于联系人数据库也是通过内容提供者暴露出来,所以直接通过内容解析者去操作数据库
ContentValues contentValues= new ContentValues();
int contact_id=count+1;
contentValues.put("contact_id",contact_id);
getContentResolver().insert(uri,contentValues);
//把name,phone,email三个字段值同步到数据库的datano表
ContentValues nameValues=new ContentValues();
nameValues.put("data1", name);//把数据插入到data1列
nameValues.put("raw_contact_id",contact_id);//告诉数据库,我们插入的数据属于那条联系人
nameValues.put("mimetype","vnd.android.cursor.item/name");//告诉数据库插入的数据的数据类型
getContentResolver().insert(datauri,nameValues);
//把name,phone,email三个字段值同步到数据库的datano表
ContentValues phoneValues=new ContentValues();
phoneValues.put("data1", phone);//把数据插入到data1列
phoneValues.put("raw_contact_id",contact_id);//告诉数据库,我们插入的数据属于那条联系人
phoneValues.put("mimetype","vnd.android.cursor.item/phone_v2");//告诉数据库插入的数据的数据类型
getContentResolver().insert(datauri,phoneValues);
//把name,phone,email三个字段值同步到数据库的datano表
ContentValues emailValues=new ContentValues();
emailValues.put("data1", email);//把数据插入到data1列
emailValues.put("raw_contact_id",contact_id);//告诉数据库,我们插入的数据属于那条联系人
emailValues.put("mimetype","vnd.android.cursor.item/email_v2");//告诉数据库插入的数据的数据类型
getContentResolver().insert(datauri,emailValues);
}
}
5、附联系人数据库关键表
data表
mimeType表
最终结果
界面
联系人列表
10.内容观察者
1、清单文件中注册要观察的权限,这里是联系人的读写权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
2、主activity文件
观察uri的改变,这里是通过读取消息中心的消息来观察的。因此上例中要添加响应的消息发送语句。这里的uri式样上例执行添加联系人操作
package com.fengray.ex078;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.ContentValues;
import android.database.ContentObservable;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private String permssionRequestCode []={Manifest.permission.READ_CONTACTS,Manifest.permission.WRITE_CONTACTS};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, permssionRequestCode,0);
ActivityCompat.requestPermissions(this, permssionRequestCode,1);
//注册内容观察者
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
getContentResolver().registerContentObserver(uri, true,new MyConentObserver(new Handler()));
}
//定义一个内容观察者
private class MyConentObserver extends ContentObserver{
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public MyConentObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
Log.d("TAG", "onChange: 刚才数据库的内容发生了改变");
super.onChange(selfChange);
}
}
}
3、上例添加消息发送语句
//发送一条消息,说明数据发生了改变
getApplicationContext().getContentResolver().notifyChange(uri,null);
当在上例添加一个联系人的时候:
打印:
2020-08-25 15:30:05.443 12397-12397/com.fengray.ex078 D/TAG: onChange: 刚才数据库的内容发生了改变
2020-08-25 15:30:05.446 12397-12397/com.fengray.ex078 D/TAG: onChange: 刚才数据库的内容发生了改变
2020-08-25 15:30:05.928 12397-12397/com.fengray.ex078 D/TAG: onChange: 刚才数据库的内容发生了改变
2020-08-25 15:30:05.949 12397-12397/com.fengray.ex078 D/TAG: onChange: 刚才数据库的内容发生了改变
2020-08-25 15:30:05.967 12397-12397/com.fengray.ex078 D/TAG: onChange: 刚才数据库的内容发生了改变