Android Studio开发之使用内容组件Content获取通讯信息讲解及实战(附源码 包括添加手机联系人和发短信)

简介: Android Studio开发之使用内容组件Content获取通讯信息讲解及实战(附源码 包括添加手机联系人和发短信)

运行有问题或需要源码请点赞关注收藏后评论区留言

一、利用ContentResolver读写联系人

在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。 首先要给AndroidMaifest.xml中添加响应的权限配置

<!-- 存储卡读写 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAG" />
    <!-- 联系人/通讯录。包括读联系人、写联系人 -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <!-- 短信。包括发送短信、接收短信、读短信 -->
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <!-- 通话记录。包括读通话记录、写通话记录 -->
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
    <!-- 安装应用请求,Android8.0需要 -->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

下面是往手机通讯录添加联系人信息的例子 效果如下

分成三个步骤 先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱

代码

ContactAddActivity类

package com.example.chapter07;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import com.example.chapter07.bean.Contact;
import com.example.chapter07.util.CommunicationUtil;
import com.example.chapter07.util.ToastUtil;
@SuppressLint("DefaultLocale")
public class ContactAddActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "ContactAddActivity";
    private EditText et_contact_name;
    private EditText et_contact_phone;
    private EditText et_contact_email;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact_add);
        et_contact_name = findViewById(R.id.et_contact_name);
        et_contact_phone = findViewById(R.id.et_contact_phone);
        et_contact_email = findViewById(R.id.et_contact_email);
        findViewById(R.id.btn_add_contact).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_add_contact) {
            Contact contact = new Contact(); // 创建一个联系人对象
            contact.name = et_contact_name.getText().toString().trim();
            contact.phone = et_contact_phone.getText().toString().trim();
            contact.email = et_contact_email.getText().toString().trim();
            // 方式一,使用ContentResolver多次写入,每次一个字段
            CommunicationUtil.addContacts(getContentResolver(), contact);
            // 方式二,使用ContentProviderOperation一次写入,每次多个字段
            //CommunicationUtil.addFullContacts(getContentResolver(), contact);
            ToastUtil.show(this, "成功添加联系人信息");
        }
    }
}

ContactReadActivity类

package com.example.chapter07;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.chapter07.bean.Contact;
import com.example.chapter07.util.CommunicationUtil;
import com.example.chapter07.util.ToastUtil;
import com.example.chapter07.util.Utils;
import java.util.List;
public class ContactReadActivity extends AppCompatActivity {
    private TextView tv_desc;
    private LinearLayout ll_list; // 联系人列表的线性布局
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact_read);
        tv_desc = findViewById(R.id.tv_desc);
        ll_list = findViewById(R.id.ll_list);
        showContactInfo(); // 显示所有的联系人信息
    }
    // 显示所有的联系人信息
    private void showContactInfo() {
        try {
            // 读取所有的联系人
            List<Contact> contactList = CommunicationUtil.readAllContacts(getContentResolver());
            String contactCount = String.format("当前共找到%d位联系人", contactList.size());
            tv_desc.setText(contactCount);
            for (Contact contact : contactList){
                String contactDesc = String.format("姓名为%s,号码为%s",contact.name, contact.phone);
                TextView tv_contact = new TextView(this); // 创建一个文本视图
                tv_contact.setText(contactDesc);
                tv_contact.setTextColor(Color.BLACK);
                tv_contact.setTextSize(17);
                int pad = Utils.dip2px(this, 5);
                tv_contact.setPadding(pad, pad, pad, pad); // 设置文本视图的内部间距
                ll_list.addView(tv_contact); // 把文本视图添加至联系人列表的线性布局
            }
        } catch (Exception e) {
            e.printStackTrace();
            ToastUtil.show(this, "请检查是否开启了通讯录权限");
        }
    }
}

activity_contact_addXML

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp" >
        <TextView
            android:id="@+id/tv_contact_name"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="联系人姓名:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <EditText
            android:id="@+id/et_contact_name"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="3dp"
            android:layout_marginTop="3dp"
            android:layout_toRightOf="@+id/tv_contact_name"
            android:background="@drawable/editext_selector"
            android:gravity="left|center"
            android:hint="请输入联系人姓名"
            android:inputType="text"
            android:maxLength="12"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </RelativeLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp" >
        <TextView
            android:id="@+id/tv_contact_phone"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="联系人号码:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <EditText
            android:id="@+id/et_contact_phone"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="3dp"
            android:layout_marginTop="3dp"
            android:layout_toRightOf="@+id/tv_contact_phone"
            android:background="@drawable/editext_selector"
            android:gravity="left|center"
            android:hint="请输入联系人手机号码"
            android:inputType="number"
            android:maxLength="11"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </RelativeLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp" >
        <TextView
            android:id="@+id/tv_contact_email"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="联系人邮箱:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <EditText
            android:id="@+id/et_contact_email"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="3dp"
            android:layout_marginTop="3dp"
            android:layout_toRightOf="@+id/tv_contact_email"
            android:background="@drawable/editext_selector"
            android:gravity="left|center"
            android:hint="请输入联系人邮箱"
            android:inputType="textEmailAddress"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </RelativeLayout>
    <Button
        android:id="@+id/btn_add_contact"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="添加联系人"
        android:textColor="@color/black"
        android:textSize="17sp" />
</LinearLayout>

activity_contact_readXML

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/tv_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textColor="@color/black"
        android:textSize="17sp" />
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:id="@+id/ll_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" />
    </ScrollView>
</LinearLayout>

二、利用ContentObserver监听短信

ContentRslover获取数据采用的是主动查询方式,有查询才有数据否则美哟。为了省事,这时用到了ContentObserver内容观察器,事先给目标内容注册一个观察器,目标内容的数据一旦发生变化,就马上触发观察器的监听事件,从而执行开发者预先定义的代码

内容观察器的用法与内容提供器类似,下面是交互方法说明

registerContentObserver 内容解析器要注册内容观察器

unregisterContentObserver 注销

notifyChange 通知内容观察器发生了数据变化

java类代码

MonitorSmsActivity

package com.example.chapter07;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
@SuppressLint("DefaultLocale")
public class MonitorSmsActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "MonitorSmsActivity";
    private static TextView tv_check_flow;
    private static String mCheckResult;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_monitor_sms);
        tv_check_flow = findViewById(R.id.tv_check_flow);
        tv_check_flow.setOnClickListener(this);
        findViewById(R.id.btn_check_flow).setOnClickListener(this);
        initSmsObserver();
    }
    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_check_flow) {
            //查询数据流量,移动号码的查询方式为发送短信内容“18”给“10086”
            //电信和联通号码的短信查询方式请咨询当地运营商客服热线
            //跳到系统的短信发送页面,由用户手工发短信
            //sendSmsManual("10086", "18");
            //无需用户操作,自动发送短信
            sendSmsAuto("10086", "18");
        } else if (v.getId() == R.id.tv_check_flow) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("收到流量校准短信");
            builder.setMessage(mCheckResult);
            builder.setPositiveButton("确定", null);
            builder.create().show();
        }
    }
    // 跳到系统的短信发送页面,由用户手工编辑与发送短信
    public void sendSmsManual(String phoneNumber, String message) {
        Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + phoneNumber));
        intent.putExtra("sms_body", message);
        startActivity(intent);
    }
    // 短信发送事件
    private String SENT_SMS_ACTION = "com.example.storage.SENT_SMS_ACTION";
    // 短信接收事件
    private String DELIVERED_SMS_ACTION = "com.example.storage.DELIVERED_SMS_ACTION";
    // 无需用户操作,由App自动发送短信
    public void sendSmsAuto(String phoneNumber, String message) {
        // 以下指定短信发送事件的详细信息
        Intent sentIntent = new Intent(SENT_SMS_ACTION);
        sentIntent.putExtra("phone", phoneNumber);
        sentIntent.putExtra("message", message);
        PendingIntent sentPI = PendingIntent.getBroadcast(this, 0,
                sentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        // 以下指定短信接收事件的详细信息
        Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION);
        deliverIntent.putExtra("phone", phoneNumber);
        deliverIntent.putExtra("message", message);
        PendingIntent deliverPI = PendingIntent.getBroadcast(this, 1,
                deliverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        // 获取默认的短信管理器
        SmsManager smsManager = SmsManager.getDefault();
        // 开始发送短信内容。要确保打开发送短信的完全权限,不是那种还需提示的不完整权限
        smsManager.sendTextMessage(phoneNumber, null, message, sentPI, deliverPI);
    }
    private Handler mHandler = new Handler(); // 声明一个处理器对象
    private SmsGetObserver mObserver; // 声明一个短信获取的观察器对象
    private static Uri mSmsUri; // 声明一个系统短信提供器的Uri对象
    private static String[] mSmsColumn; // 声明一个短信记录的字段数组
    // 初始化短信观察器
    private void initSmsObserver() {
        //mSmsUri = Uri.parse("content://sms/inbox");
        //Android5.0之后似乎无法单独观察某个信箱,只能监控整个短信
        mSmsUri = Uri.parse("content://sms"); // 短信数据的提供器路径
        mSmsColumn = new String[]{"address", "body", "date"}; // 短信记录的字段数组
        // 创建一个短信观察器对象
        mObserver = new SmsGetObserver(this, mHandler);
        // 给指定Uri注册内容观察器,一旦发生数据变化,就触发观察器的onChange方法
        getContentResolver().registerContentObserver(mSmsUri, true, mObserver);
    }
    // 在页面销毁时触发
    protected void onDestroy() {
        super.onDestroy();
        getContentResolver().unregisterContentObserver(mObserver); // 注销内容观察器
    }
    // 定义一个短信获取的观察器
    private static class SmsGetObserver extends ContentObserver {
        private Context mContext; // 声明一个上下文对象
        public SmsGetObserver(Context context, Handler handler) {
            super(handler);
            mContext = context;
        }
        // 观察到短信的内容提供器发生变化时触发
        public void onChange(boolean selfChange) {
            String sender = "", content = "";
            // 构建一个查询短信的条件语句,移动号码要查找10086发来的短信
            String selection = String.format("address='10086' and date>%d",
                    System.currentTimeMillis() - 1000 * 60 * 1); // 查找最近一分钟的短信
            // 通过内容解析器获取符合条件的结果集游标
            Cursor cursor = mContext.getContentResolver().query(
                    mSmsUri, mSmsColumn, selection, null, " date desc");
            // 循环取出游标所指向的所有短信记录
            while (cursor.moveToNext()) {
                sender = cursor.getString(0); // 短信的发送号码
                content = cursor.getString(1); // 短信内容
                Log.d(TAG, "sender="+sender+", content="+content);
                break;
            }
            cursor.close(); // 关闭数据库游标
            mCheckResult = String.format("发送号码:%s\n短信内容:%s", sender, content);
            // 依次解析流量校准短信里面的各项流量数值,并拼接流量校准的结果字符串
            String flow = String.format("流量校准结果如下:总流量为:%s;已使用:%s" +
                            ";剩余流量:%s", findFlow(content, "总流量为"),
                    findFlow(content, "已使用"), findFlow(content, "剩余"));
            if (tv_check_flow != null) { // 离开该页面后就不再显示流量信息
                tv_check_flow.setText(flow); // 在文本视图显示流量校准结果
            }
            super.onChange(selfChange);
        }
    }
    // 解析流量短信里面的流量数值
    private static String findFlow(String sms, String begin) {
        String flow = findString(sms, begin, "GB");
        String temp = flow.replace("GB", "").replace(".", "");
        if (!temp.matches("\\d+")) {
            flow = findString(sms, begin, "MB");
        }
        return flow;
    }
    // 截取指定头尾之间的字符串
    private static String findString(String content, String begin, String end) {
        int begin_pos = content.indexOf(begin);
        if (begin_pos < 0) {
            return "未获取";
        }
        String sub_sms = content.substring(begin_pos);
        int end_pos = sub_sms.indexOf(end);
        if (end_pos < 0) {
            return "未获取";
        }
        if (end.equals(",")) {
            return sub_sms.substring(begin.length(), end_pos);
        } else {
            return sub_sms.substring(begin.length(), end_pos + end.length());
        }
    }
}

XML文件代码

activity_monitor_smsXML

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <Button
        android:id="@+id/btn_check_flow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="发送校准短信"
        android:textColor="@color/black"
        android:textSize="17sp" />
    <TextView
        android:id="@+id/tv_check_flow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:textColor="@color/black"
        android:textSize="17sp" />
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~~

相关文章
|
12天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
38 19
|
12天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
37 14
|
13天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
在数字时代,掌握安卓应用开发技能是进入IT行业的关键。本文将引导读者从零基础开始,逐步深入安卓开发的世界,通过实际案例和代码示例,展示如何构建自己的第一个安卓应用。我们将探讨基本概念、开发工具设置、用户界面设计、数据处理以及发布应用的全过程。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上迈出坚实的步伐。
25 5
|
11天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
13天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
12天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
13天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
21 0
|
7月前
|
存储 Java 开发工具
Android开发的技术与开发流程
Android开发的技术与开发流程
406 1
|
4月前
|
安全 Android开发 Swift
安卓与iOS开发:平台差异与技术选择
【8月更文挑战第26天】 在移动应用开发的广阔天地中,安卓和iOS两大平台各占一方。本文旨在探索这两个系统在开发过程中的不同之处,并分析开发者如何根据项目需求选择合适的技术栈。通过深入浅出的对比,我们将揭示各自平台的优势与挑战,帮助开发者做出更明智的决策。
77 5
|
4月前
|
移动开发 搜索推荐 Android开发
安卓与iOS开发:一场跨平台的技术角逐
在移动开发的广阔舞台上,两大主角——安卓和iOS,持续上演着激烈的技术角逐。本文将深入浅出地探讨这两个平台的开发环境、工具和未来趋势,旨在为开发者揭示跨平台开发的秘密,同时激发读者对技术进步的思考和对未来的期待。