移动应用开发实验-内容提供者-ContentResolver的使用

news2024/11/29 10:56:04

文章目录

  • 前言
  • 读取通讯录信息
    • 要求
    • 环境
  • 具体实现
    • 主页面布局(activity_main.xml)
    • 关于RecyclerView库的相关问题
      • 添加RecyclerView库操作
    • 解决报错
    • Item布局(info.xml)
    • 添加访问权限
    • 编写实体类(ContactInfo.java)
    • 编写适配器(MyAdapter.java)
    • 编写主类(MainActivity.java)
  • 运行测试

前言

  • 本人将所学和前人的成果和经验结合,仅供学习和参考!!!
  • 本文大部分源码内容有清晰的注释,请认真阅读!

读取通讯录信息

要求

  • 通过线性布局和相对布局来搭建通讯录界面,界面效果如下图所示。创建布局文件contact_item.xml、导入界面图片、放置界面控件、创建条目界面的背景文件。创建ContactInfo类、在该类中创建联系人信息的属性。申请读取手机通讯录的权限,将数据显示到通讯录界面上。在AndroidMainfest.xml文件中添加读取系统通讯录的权限。运行Contacts程序,查看通讯录界面效果。
    在这里插入图片描述

环境

  • minSdk 24
  • targetSdk 33
  • sourceCompatibility JavaVersion.VERSION_1_8
  • targetCompatibility JavaVersion.VERSION_1_8
  • gradle-7.5
  • Android Studio Electric Eel | 2022.1.1 Patch 1
  • 知识储备:RecyclerView布局和ContentResolver的内容学习储备

具体实现

  • 记得提前将需要的头像图片导入到drawable目录下

主页面布局(activity_main.xml)

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="通讯录"
        android:gravity="center"
        android:background="#4889f4"
        android:textColor="@color/white"
        android:textSize="20sp"
        />
    <androidx.recyclerview.widget.RecyclerView
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:id="@+id/list"
        android:layout_height="wrap_content"
        />

</LinearLayout>

关于RecyclerView库的相关问题

  • 建议:该本地环境中,如果可以正常使用RecyclerView布局,即可不用引入RecyclerView库依赖,好像在其他的包中已经默认包含(亲测,正常运行程序)
  • 如果,要引入,请参考一下操作

添加RecyclerView库操作

在这里插入图片描述
在这里插入图片描述

com.android.support:recyclerview-v7

在这里插入图片描述

  • 然后,可以在Android视图下,模块的build.grade配置文件dependencies中看到添加的依赖

解决报错

  • 在Android视图下,模块的build.properties配置文件中添加
android.useAndroidX=true #如果该项本来存在,则不用添加
android.enableJetifier=true

Item布局(info.xml)

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<!--item布局文件-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:orientation="horizontal"
    >
    <ImageView
        android:id="@+id/iv"
        android:layout_width="66dp"
        android:layout_height="67dp"
        android:src="@drawable/contact_photo"
        />
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp">
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:textColor="#ff8f03" />

        <TextView
            android:id="@+id/telephoneNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:layout_marginTop="10dp"
            android:layout_below="@+id/name"
            android:textColor="#ff716c6d"
            android:maxLines="2"
            android:ellipsize="end"/>
    </RelativeLayout>

</LinearLayout>

添加访问权限

  • AndroidMainfest.xmlapplication上边标签添加通讯录访问权限
<!--添加读取系统通讯录的权限-->
<uses-permission android:name="android.permission.READ_CONTACTS" />

编写实体类(ContactInfo.java)

/**
 * 实体类,用于存储联系人信息
 */
public class ContactInfo {
    private String name, telephoneNumber;

    public String getName() {
        return name;
    }

    public String getTelephoneNumber() {
        return telephoneNumber;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setTelephoneNumber(String telephoneNumber) {
        this.telephoneNumber = telephoneNumber;
    }
}

编写适配器(MyAdapter.java)

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

/**
 * 自定义类实现数据适配
 */
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
    private Context myContext;
    private List<ContactInfo> myContactInfos;
    public MyAdapter(Context context,List<ContactInfo> contactInfoList){
        this.myContext=context;
        this.myContactInfos=contactInfoList;
    }

    /**
     * 加载item界面的布局文件,并将RecyclerView.ViewHolder类的对象返回
     * @param parent The ViewGroup into which the new View will be added after it is bound to
     *               an adapter position.
     * @param viewType The view type of the new View.
     *
     * @return
     */
    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view=View.inflate(myContext,R.layout.info,null);
        MyHolder myHolder=new MyHolder(view);
        return myHolder;
    }

    /**
     * onBindViewHolder 将获取的数据设置到对应的控件上
     * @param holder The ViewHolder which should be updated to represent the contents of the
     *        item at the given position in the data set.
     * @param position The position of the item within the adapter's data set.
     */
    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
        ContactInfo contactInfo=myContactInfos.get(position);
        holder.name.setText(contactInfo.getName());
        holder.telephoneNumber.setText(contactInfo.getTelephoneNumber());
    }

    /**
     * 获取列表条目总数
     * @return
     */
    @Override
    public int getItemCount() {
        return myContactInfos.size();
    }

    /**
     * 创建MyHolder类,继承RecyclerView.ViewHolder类,在该类中获取Item界面上的控件
     */
    class MyHolder extends RecyclerView.ViewHolder{

        TextView name,telephoneNumber;
        public MyHolder(@NonNull View itemView) {
            super(itemView);
            name=itemView.findViewById(R.id.name);
            telephoneNumber=itemView.findViewById(R.id.telephoneNumber);
        }
    }
}

编写主类(MainActivity.java)


import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private RecyclerView list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //申请权限
        getPermission();

        // 获取RecyclerView控件
        list=findViewById(R.id.list);
        // 设置item分割线
        list.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
        // 设置RecyclerView的显示方式为垂直布局
        list.setLayoutManager(new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,true));
        // 通过setAdapter方法将适配器对象设置到RecyclerView控件上
        MyAdapter myAdapter=new MyAdapter(this,getContacts());
        list.setAdapter(myAdapter);

    }

    /**
     * 申请权限
     */
    public void getPermission(){
        //检查权限是否允许
        if (ActivityCompat.checkSelfPermission(this,"android.permission.READ_CONTACTS")!= PackageManager.PERMISSION_GRANTED){
            //请求android.permission.READ_CONTACTS权限
            ActivityCompat.requestPermissions(this,new String[]{"android.permission.READ_CONTACTS"},666);
            //shouldShowRequestPermissionRationale 检查是否需要展示请求权限的提示
            //首次运行程序时,选择允许权限访问,之后再次打开应用就不会出现请求权限的提示
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,"android.permission.READ_CONTACTS")){
                Toast.makeText(this, "需要开启联系人权限", Toast.LENGTH_SHORT).show();
            }else {
                ActivityCompat.requestPermissions(this,new String[]{"android.permission.READ_CONTACTS"},666);
            }
        }
    }

    /**
     * 手动请求权限之后的结果回调
     * @param requestCode 请求吗
     * @param permissions 系统的权限数据
     * @param grantResults 请求码的状态
     *
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode==666){
            /*
                判断权限数组中是否有一个状态值为android.permission.READ_CONTACTS 该状态值表示允许读取系统短信。
                如果有该状态值,提示联系人权限申请成功,否则,失败
            * */
            for (int i=0;i<permissions.length;i++){
                if(permissions[i].equals("android.permission.READ_CONTACTS") && grantResults[i]==PackageManager.PERMISSION_GRANTED){
                    Toast.makeText(this, "联系人权限申请成功", Toast.LENGTH_SHORT).show();
                    return;
                }
            }
            Toast.makeText(this, "联系人权限申请失败", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 通过ContactInfo类和cursor遍历获取系统通讯录的联系人信息
     * @return
     */
    public List<ContactInfo> getContacts(){
        List<ContactInfo> contactInfos=new ArrayList<>();
        Cursor cursor01=getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
        while (cursor01.moveToNext()){
            ContactInfo contactInfo=new ContactInfo();
            String Name,phone,id;
            //获取name,并存入contactInfo
            Name=cursor01.getString(cursor01.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
            contactInfo.setName(Name);
            id=cursor01.getString(cursor01.getColumnIndexOrThrow(ContactsContract.Contacts._ID));

            //获取phoneNumber,并存入contactInfo
            Cursor cursor02=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+id,null,null);
            while (cursor02.moveToNext()){
                phone=cursor02.getString(cursor02.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER));
                contactInfo.setTelephoneNumber(phone);
            }
            //将其contactInfo存入contactInfos集合中
            contactInfos.add(contactInfo);
            //关闭游标
            cursor02.close();
        }
        cursor01.close();
        //最终返回list集合
        return contactInfos;
    }

}

运行测试

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/523914.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

20 散列表的查找

散列表的查找 简介&#xff1a;散列表&#xff08;也成哈希表&#xff09;是一种高效的数据结构&#xff0c;他可以在平均复杂度为O(1)的情况下实现查找、插入和删除操作。 哈希表的基本思想是根据关键字的值来计算其应存储的位置。这个计算过程就是通过哈希函数来实现的。 根…

计算机视觉——day 91基于双网络的鲁棒特征高光谱目标检测(偏门且很水啊)

基于双网络的鲁棒特征高光谱目标检测 I. INTRODUCTIONII. 提出的方法A. 总体框架B.训练集构建C. Dual Networks III. EXPERIMENTSIV. 结论 I. INTRODUCTION 用于高光谱目标检测的深度网络训练通常面临样本有限的问题&#xff0c;在极端情况下&#xff0c;可能只有一个目标样本…

黑盒测试方法

1 等价类划分 1.1 定义 等价类划分法是一种典型的&#xff0c;并且是最基础的黑盒测试用例设计方法。采用等价类划分法时&#xff0c;完全不用考虑程序内部结构&#xff0c;设计测试用例的唯一依据是软件需求规格说明书。 所谓等价类&#xff0c;是输入条件的一个子集合&…

kali整体版本更新方法,为啥更新?

玩过kali都知道&#xff0c;如果不更新版本&#xff0c;那么安装某个软件总是有很多依赖版本问题&#xff0c;解决起来的确麻烦&#xff0c;这篇文章彻底解决这些问题。 1&#xff0c;更新源 国外源与国内源的选择 kali默认配置的是国外源&#xff0c;但国外源的下载速度非常慢…

基于容器和Kubernetes的应用无限扩容

基于应用负载动态管理CPU、内存等资源的使用是云原生架构的最佳实践之一&#xff0c;Kubernetes通过资源请求和限制以及HPA/VPA等机制&#xff0c;为云原生应用资源管理提供了很好的支持。原文: Infinite Scaling with Containers and Kubernetes[1] 如果没有足够资源让容器完成…

matlab第八章_Simulink简介

目录 Simulink简介 基本知识 Simulink组成 模块库简介 Simulink系统仿真 Stateflow建模与应用 Stateflow的定义 状态图编辑器 Stateflow流程图 Simulink简介 基本知识 Simulink是实现动态系统建模&#xff0c;仿真和分析的软件包&#xff0c;被广泛应用于线性系统&…

土地报征简介

报征概念&#xff1a; 土地报征是指国家为了人民整体利益出发&#xff0c;根据我国相关法律和法规的要求和流程&#xff0c; 将集体土地性质转化为国有土地性质&#xff0c;并给予被征地的对象给予合理的补偿和安置工作。报征4个价段&#xff1a; 1、组卷阶段 &#xff08;1&…

Linux系统之top命令的基本使用

Linux系统之top命令的基本使用 一、top命令介绍二、检查本地环境1. 检查操作系统版本2. 检查系统内核版本 三、top命令的使用帮助1. top命令的选项2. top命令的交换命令 四、top显示信息解释1. top的第一行解释2. top的第二、三行信息解释3. top的第四、五行信息解释4. top的进…

Java 常用注解的使用

在Java中&#xff0c;注解&#xff08;Annotation&#xff09;是一种元数据&#xff0c;它提供了一种机制&#xff0c;可以将元数据与代码一起存储&#xff0c;并使其可用于编译器、解释器或其他工具的处理。注解可以在Java源代码中添加元数据&#xff0c;以提供更多的信息&…

【Linux】Linux基本指令(3)

一.时间的相关指令 date显示 单纯的输入 date 会以这种形式输出&#xff1a; 但其实这种形式我们看着是不太习惯的&#xff0c;我们可以指定形式输出&#xff1a; 格式为&#xff1a;date 选项 %H : 小时(00..23) %M : 分钟(00..59) %S : 秒(00..61) %X : 相当于 %H:%M:%S %d …

Qt扫盲-QPieSlice理论总结

QPieSlice理论总结 一、概述二、标签三、属性设置四、信号说明 一、概述 QPieSlice 类表示饼图中的单个QPieSlice。饼图QPieSlice有一个值和一个标签。将QPieSlice添加到饼图时&#xff0c;QPieSeries对象将自动计算QPieSlice的百分比&#xff0c;并与序列中所有QPieSlice的总…

Java SE(十一)之包装类(各种类型之间的转换)

文章目录 Object类 &Number类1.Object2.Number类 包装类&#xff0c;装箱&#xff0c;拆箱1.手动装箱/拆箱2.自动装箱/ 拆箱 应用——常见包装类1.Integer类2.Character类3.实战——各种类型之间的转换&#xff08;1&#xff09;int和Integer相互转换&#xff08;2&#xf…

20230514-SmartChat测试效果图

E:\20230514-SmartChat测试效果图您好&#xff0c;我是SmartChat&#xff0c;新生代智能机器人&#xff0c;通过运用自然语言处理、机器学习和人工智能等高精尖技术&#xff0c;可以与您进行自然、流畅、有趣的对话&#xff0c;帮助您获取所需的信息和服务。无论您想要写商业计…

如何提高跨职能团队的绩效和成果

在50年代&#xff0c;当计算机仍被视为复杂的计算器时&#xff0c;西北互助人寿保险公司就计算机对未来业务的影响进行了研究。有趣的是&#xff0c;该公司的首席执行官为这项研究设立了一个不同寻常的团队——由来自多个部门的员工组成&#xff0c;每个人都看到了计算机在保险…

redis批处理任务,多线程 or pipeline

前言 工作中使用redis的时候遇到一个问题&#xff0c;如果我们要对存储在redis中的一批数据进行操作&#xff0c;为了加快处理的速度&#xff0c;我们一般有两种方式&#xff1a; 建立多个线程&#xff0c;使用多个连接发送请求使用redis提供的pipeline 引发了一个小思考&…

股票量价关系基础知识9----图解各阶段量价关系:价平量平

价平量平是指股价涨跌幅度不大&#xff0c;成交量持平&#xff0c;反映多空双方受不明朗因素困扰&#xff0c;均对后市走势持观望态度&#xff0c;投资者在此阶段不宜盲目入市&#xff0c;但具体到某一阶段又略有差异。 一、上涨初期的价平量平 &#xff08;一&#xff09;形态…

深度学习之图像分类(二):ZFNet

本专栏介绍基于深度学习进行图像识别的经典和前沿模型&#xff0c;将持续更新&#xff0c;包括不仅限于&#xff1a;AlexNet&#xff0c; ZFNet&#xff0c;VGG&#xff0c;GoogLeNet&#xff0c;ResNet&#xff0c;DenseNet&#xff0c;SENet&#xff0c;MobileNet&#xff0c…

SpringBoot 2.0 + Nacos + Sentinel 流控规则集中存储

前言 Sentinel 原生版本的规则管理通过API 将规则推送至客户端并直接更新到内存中&#xff0c;并不能直接用于生产环境。不过官方也提供了一种 Push模式&#xff0c;扩展读数据源ReadableDataSource&#xff0c;规则中心统一推送&#xff0c;客户端通过注册监听器的方式时刻监…

四轴飞控DIY Mark4 - 优化后续二

四轴飞控DIY Mark4 - 优化后续二 1. 源由2. 优化方案3. 实现细节3.1 锡箔屏蔽3.2 热缩管固定3.3 电池地接地3.4 更换飞控 4. 整体效果4.1 配置4.2 Roll&Pitch波形4.3 电机波形 5. 结论6. 附录&#xff1a;FPV Quad GPS cable sheilding 1. 源由 Betaflight BN880 GPS 简单测…

Qt扫盲-QPieSeries理论总结

QPieSeries理论总结 一、概述二、简单的使用1. 创建 QPieSeries 并赋值2. 自定义显示 QPieSlice3. 初始化绘图设备&并关联上图4. 把绘图设备框架放置在 Gui 控件上5. 完整代码 三、镂空饼状图1. 初始化 QPieSeries 和 QPieSlice2. 初始化绘图设备&并关联上图3. 把绘图设…