黑马Android76期学习笔记01基础--day09--ContentProvider、内容解析者,内容观察者

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: 刚才数据库的内容发生了改变

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值