【安卓实现手机通讯录】开发总结

article/2025/9/15 18:01:39

Android实现手机通讯录

  • 总结遇到的问题
    • 一、 权限
    • 安卓的权限主要分为
    • 问题
    • 二、Android studio 数据库可视化操作
    • 三、数据库查找工作
      • 1、查找联系人信息
      • 2、如何异步查询短信记录
    • 四、Intent 传送数据
      • 1.使用方式一:
      • 2.使用方法二:
    • 五、运行时的错误
      • 1.空指针异常
      • 2.内存溢出

总结遇到的问题

一、 权限

安卓的权限主要分为

普通权限:
涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。这些权限在应用安装时授予,运行时不再询问用户。例如: 网络访问、WIFI状态、音量设置等。

危险权限:
涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如: 读取通讯录、读写存储器数据、获取用户位置等。如果应用声明需要这些危险权限,则必须在运行时明确告诉用户,让用户手动授予。

特殊权限:
SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS 这两个权限比较特殊,不能通过代码申请方式获取,必须得用户打开软件设置页手动打开,才能授权。
注意:
当获取危险权限时
在运行程序时,除了在Manifest文件中定义,还需要模拟器在运行时,手动添加权限原来Android虚拟机权限需要手动添加:
在 所有应用 中,找到你的程序,点开应用信息,然后手动添加 “权限”。
常用的危险权限如下:
请添加图片描述

问题

当编译完app之后,在我自己手机上运行时,闪退不能运行,原来是因为我没有自己手动设置应用权限
解决
在MainActivity界面添加代码,即实现在app运行时,询问用户开启权限,这样用户就不会在第一次使用时无法打开app,一头雾水了

 /*** 权限处理* //处理权限请求* //首先定义一个变量来记录处理权限了几次* 该代码实现了一次同时询问多个权限。*/private int times = 0;//在处理权限时的回调private final int REQUEST_PHONE_PERMISSIONS = 0;//检查全新的核心方法private void checkPermission() {times++;final List<String> permissionsList = new ArrayList<>();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//获取权限,将需要获取的权限添加入list;if ((checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED))permissionsList.add(Manifest.permission.READ_CONTACTS);if ((checkSelfPermission(Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED))permissionsList.add(Manifest.permission.WRITE_CONTACTS);if ((checkSelfPermission(Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED))permissionsList.add(Manifest.permission.READ_CALL_LOG);if ((checkSelfPermission(Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED))permissionsList.add(Manifest.permission.SEND_SMS);if ((checkSelfPermission(Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED))permissionsList.add(Manifest.permission.READ_SMS);if ((checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED))permissionsList.add(Manifest.permission.CALL_PHONE);if (permissionsList.size() != 0) {if (times==1) {//申请结果的主要部分就为下面这一句requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),REQUEST_PHONE_PERMISSIONS);} else {new AlertDialog.Builder(this).setCancelable(true).setTitle("提示").setMessage("获取不到授权,APP将无法正常使用,请在设置中允许APP获取权限!").setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface arg0, int arg1) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),REQUEST_PHONE_PERMISSIONS);}}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface arg0, int arg1) {finish();//这里对该界面直接进行销毁,让用户从新进入该界面}}).show();}} else {//initData();//初始化数据}} else {//initData();//初始化数据}}//权限处理的回调,当用户提出权限访问时,系统会返回结果,该方法中处理结果。@Overridepublic void onRequestPermissionsResult(int requestCode, final String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);checkPermission();}

二、Android studio 数据库可视化操作

操作步骤:

  1. 需要下载插件,但该插件不是免费下载,需要破解
    安装数据库插件SQLScout,操作目录为:File->setting->plugings,搜索SQLcount 点击install 即可获得一天的使用,成功后Android studio右边栏会出现“SQLite Explrer”

  2. 连上手机或模拟器,打开“Device File Explorer”,通过右边栏“Device File Explorer”直接打开,或者“View”—>“Tool Windows”—>“Device File Explorer”

  3. 进入目录data/data/app包名/databases/,双击数据库文件,然后点击"SQLite Explorer"即可对数据查看和操作,如果发生Error downloading contents of device file “xx.db”: open failed: Permission,命令行执行“adb root”即可

  4. 除了下载在AndroidStudio 下载 SQL Count 插件外,也可自己下载一个工具软件
    在这里插入图片描述
    百度搜索即可免费下载,但使用过程有点麻烦,需要导出数据库中的”xx.db“ ,找到需要查看的db文件,右键save as 即可保存,再使用该软件即可打开查看数据库中的内容。

三、数据库查找工作

1、查找联系人信息

private void getPhoneContacts() {ContentResolver resolver = this.getContentResolver();
// 获取手机联系人Cursor phoneCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PHONES_PROJECTION, null,null, null);if (phoneCursor != null) {while (phoneCursor.moveToNext()) {//得到手机号码String phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX);//当手机号码为空的或者为空字段 跳过当前循环if (TextUtils.isEmpty(phoneNumber))continue;//得到联系人名称String contactName = phoneCursor.getString(PHONES_DISPLAY_NAME_INDEX);//得到联系人 IDLong contactid = phoneCursor.getLong(PHONES_CONTACT_ID_INDEX);//得到联系人头像 IDLong photoid = phoneCursor.getLong(PHONES_PHOTO_ID_INDEX);//得到联系人头像 BitampBitmap contactPhoto = null;//photoid 大于 0 表示联系人有头像 如果没有给此人设置头像则给他一个默认的if (photoid > 0) {Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactid);InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(resolver, uri);contactPhoto = BitmapFactory.decodeStream(input);} else {//设置默认头像contactPhoto = BitmapFactory.decodeResource(getResources(), R.drawable.touxiang1);}myPhone mp = new myPhone(contactid, phoneNumber, contactName, null, null, null, null, null);myPhoneuserList.add(mp);
//                mContactsPhonto.add(contactPhoto);Log.d("获取", "getPhoneContacts: " + contactName + " phoneNumber " + phoneNumber + " photoid " + photoid);}phoneCursor.close();Log.d("获取", "获取联系人列表完成");}}

2、如何异步查询短信记录

(自行理解吧。。。)

private ListView talkView;private List<MessageBean> messages = null;private AsyncQueryHandler asyncQuery;private String address;private SimpleDateFormat sdf;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.message_list_view);sdf = new SimpleDateFormat("MM-dd HH:mm");String threadid = getIntent().getStringExtra("threadid");init(threadid);Log.v("messageBoxList",messages.size()+"");}
//定义init() 方法,实现查询private void init(String thread) {asyncQuery = new MessageAsynQueryHandler(getContentResolver());talkView = (ListView) findViewById(R.id.message_list);messages = new ArrayList<MessageBean>();Uri uri = Uri.parse("content://sms");String[] projection = new String[] { "date", "address", "person", "body", "type" }; // 查询的列asyncQuery.startQuery(0, null, uri, projection, "thread_id = " + thread, null, "date asc");}
/*** 异步查询数据库的类* 查找对应用户的消息对话,*/private class MessageAsynQueryHandler extends AsyncQueryHandler {public MessageAsynQueryHandler(ContentResolver cr) {super(cr);}@SuppressLint("Range")//cursor 会报出value > 0 的错误 ,对于cursor查找应该对应的index必须大于等于0,但为了规范,是通过getColumIndex查找,报出错误,所以加上警告提示@Overrideprotected void onQueryComplete(int token, Object cookie, Cursor cursor) {if (cursor != null && cursor.getCount() > 0) {cursor.moveToFirst();for (int i = 0; i < cursor.getCount(); i++) {cursor.moveToPosition(i);String date = sdf.format(new Date(cursor.getLong(cursor.getColumnIndex("date"))));if (cursor.getInt(cursor.getColumnIndex("type")) == 1) {// 他说的信息MessageBean d = new MessageBean(cursor.getString(cursor.getColumnIndex("address")),date,cursor.getString(cursor.getColumnIndex("body")),R.layout.message_list_say_he_item);messages.add(d);} else { // MessageBean为自定义的短信实体类,用于保存每一条短信的相关内容,如短信内容,发送日期,发送地址等MessageBean d = new MessageBean(cursor.getString(cursor.getColumnIndex("address")),date,cursor.getString(cursor.getColumnIndex("body")), R.layout.message_list_say_me_item);messages.add(d);}}if (messages.size() > 0) {//talkView为listview 用于展示短信内容talkView.setAdapter(new MessageBoxListAdapter(MessageBoxList.this, messages));talkView.setDivider(null);talkView.setSelection(messages.size());} else {Log.v("messageBoxList","没有数据显示");Toast.makeText(MessageBoxList.this, "没有短信进行操作",Toast.LENGTH_SHORT).show();}}Log.d("messageBoxList",cursor.getCount()+"");super.onQueryComplete(token, cookie, cursor);}}

四、Intent 传送数据

通过Intent 调用,可以实现页面的跳转,进行数据传送

1.使用方式一:

通过putExtra() 方法

Intent intent = new Intent(MainActivity.this, SecondActivity.class);intent.putExtra("key", "value");startActivity(intent);// 或者可一定义bundle
Intent intent = new Intent(MainActivity.this,SecondActivity.class);Bundle bundle = new Bundle();bundle.putLong("contactid", myPhoneuserList.get(position).getContactId());intent.putExtras(bundle);startActivity(intent);         

2.使用方法二:

通过Serializable接口
Serializable是序列化的意思,表示将一个对象转换为可存储或者可传输的状态,序列化后的对象可以在网络上进行传输,也可以存储到本地

//自定义序列化
public class MyMap implements Serializable {private Map<String, Object> map;public Map<String, Object> getMap() {return map;}public void setMap(Map<String, Object> map) {this.map = map;}
}//调用序列化存入数据
MyMap myMap = new MyMap();
myMap.setMap(your_map);//把你自己的map集合放进去
Bundle bundle = new Bundle();
Intent intent = new Intent(mActivity, OtherActivity.class);
bundle.putSerializable("map", myMap);
intent.putExtras(bundle);
startActivity(intent);
//获取数据
Bundle bundle = getIntent().getExtras();
MyMap my_map= (MyMap) bundle.get("map");
Map your_map= my_map.getMap();

五、运行时的错误

1.空指针异常

在这里插入图片描述

解决:
错误原因:因为关于Async QueryHander的调用异常 ,因为我没有在init() 方法 中
Uri uri = android.provider.CallLog.Calls.CONTENT_URI;
asynccall_contact_Query.startQuery(0, null, uri, contact_projection, null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
忘记在在这之前添加
asynccall_contact_Query = new MyAsyncQueryHandler(getContentResolver());
导致空指针异常

在这里插入图片描述

这里空指针异常,是因为在适配器中的getview方法中,没有正确的获取view,没有写上view

2.内存溢出

Java 内存溢出(java.lang.OutOfMemoryError)
原因:将cursor.moveToNext() 写成 cursor.MoveToFirst() 所以在运行之后一直没有反应,知道报出内存溢出的问题,这么粗心的问题,以后要避免再犯!!!
在这里插入图片描述

总结
Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结
java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都出于以下原因:JVM内存过小、程序不严密,产生了过多的垃圾。
导致OutOfMemoryError异常的常见原因有以下几种:

  1. 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  2. 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
  3. 代码中存在死循环或循环产生过多重复的对象实体;
  4. 使用的第三方软件中的BUG;
  5. 启动参数内存值设定的过小;
    此错误常见的错误提示:
  6. tomcat:java.lang.OutOfMemoryError: PermGen space
  7. tomcat:java.lang.OutOfMemoryError: Java heap space
  8. weblogic:Root cause of ServletException java.lang.OutOfMemoryError
  9. resin:java.lang.OutOfMemoryError java:java.lang.OutOfMemoryError

其他错误
在这里插入图片描述


http://chatgpt.dhexx.cn/article/Ehtf2CEf.shtml

相关文章

手机程序开发

如今手机已成为大众的交流工具。有关手机的程序开发越来越广泛&#xff0c;本节通过几个典型实例介绍如何利用短信猫发送、接收短信、远程控制计算机、业务员销售数据采集和短信息娱乐互动平台。 实例431 利用短信猫收发短信息 实例说明 短信猫是利用SIM卡发送短信的硬件设备&…

实战用Python+Pygame+Kivy(Buildozer)+Ubuntu开发安卓android手机端apk游戏及踩坑分享

在学习Python过程中&#xff0c;第一个接触到了Pygame和Pygame ZERO两个库&#xff0c;学完Pygame的基础知识后&#xff0c;就开始研究如何让程序在手机端运行&#xff0c;于是就开始了无尽的踩坑过程。 游戏的编写和设计就一笔略过&#xff0c;基础的源代码网上下载的&#x…

【安卓开发】

adb 查看Android版本号和SDK版本号 获取系统版本&#xff1a; adb devices adb usbadb shell getprop ro.build.version.release获取系统api版本&#xff1a; adb shell getprop ro.build.version.sdk争做数字极简主义&#xff0c;从买一台多亲2pro老年机开始 进入开发者&…

AndroidStudio连接安卓手机开发与调试

由于最近需要出去做学习汇报&#xff0c;本人就想着做一个简单的成品进行展示&#xff08;入门级&#xff09;&#xff0c;又通过这段时间的学习发现&#xff0c;用安卓手机进行调试代码&#xff0c;不仅可观还方便展示哈哈哈&#xff0c;&#xff0c;但是连接手机调试的过程中…

Android开发板

由于公司要做智能自助设备&#xff0c;因此需要在Android开发板上开发&#xff0c;记录一下经验 一、Android开发板应用 Android开发板应用&#xff1a; 商业应用&#xff1a;机顶盒、广告机&#xff0c;自助机&#xff0c;售卖机&#xff0c;多媒体教学&#xff0c;人脸识别…

0.1.2 arduinodroid安卓手机版开发工具

原料&#xff1a; 能联网的手机1个 OTG转接头1个 开发板1个 数据线1根 目的&#xff1a; 在没有电脑的环境下码代码、编译、debug、update固件 首先手机上下载安装【arduinodroid】应用 然后用数据线连接OTG手机和开发板&#xff0c; 打开软件在右上角的【...】打开设置…

Android开发技术

Android 开发技术 1.RecycleView 设置监听器2.TimepickerView使用3.EditText隐藏下划线 1.RecycleView 设置监听器 步骤&#xff1a; 1、在Adapter中新建一个接口&#xff0c;定义接口内部的方法&#xff0c;并将该接口在adapter中实现 编写回调接口的基本步骤&#xff1a; 1…

安卓手机APP 开发

最近在准备开题报告&#xff0c;已经很久没再写博客了&#xff0c;明天要开题答辩了&#xff0c;十分紧张&#xff0c;写个博客&#xff0c;放松一下&#xff0c;祝自己明天顺利通过。哈哈&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 前一阵子&#xff0c;…

利用手机、平板开发安卓APP(入门篇)

在这之前&#xff0c;开发安卓APP的开发者们只能依赖PC端的eclipse或Android studio等IDE开发软件&#xff0c;至少在您打开这篇文章时就已经证明您从未使用手机开发过安卓APP。如果您继续往下读就会相信并且确信&#xff1a;单纯使用手机、平板也能构建一个十全十美的APP应用。…

Android开发入门

文章目录 基础认识 Android作业&#xff1a;利用百度LBS定位期末作业&#xff1a;Android&#xff08;仿QQ登入网易新闻&#xff09;其他自学 基础认识 Android 开发&#xff1a;用于安卓手机APP开发 PHP&#xff1a;动态网页 Android Android系统是由Andy Rubin创建的&…

【Android开发】

系列文章目录 软工课设学习记录贴 基于android原生Java&#xff08;后端&#xff09;pythondjango 文章目录 系列文章目录一、Android Studio布局2.Activity活动2.1 活动的生命周期 3、底部导航BottomNavigationViewFragment3.1 Fragment3.2 Frame Layout 4.Intent4.1 显示Int…

android软件开发

安卓开发笔记 第一课xmlmach_parent 文件夹组成新建导入程序页面 第一课xml Linear layout:线性布局 android:orientation“vertical”&#xff08;垂直布局&#xff09; 布局属性 background"#ff0000"(设置背景色) layout_width“200dp” (dp类似像素单位) 其中字…

Android手机端编程开发软件合集(一)

【2022-05-14链接已更新】在网上搜索了很久才找到的编程IDE高级解锁版&#xff0c; 在这里记录并分享一下吧&#xff01; 一、合集地址&#xff1a; 蓝奏云&#xff1a;https://huanxingke.lanzoux.com/b0203kqjg 密码&#xff1a;flyingdream 二、软件合集截图如下&#xff…

python实现Gabor滤波器

Gabor 函数表示 复数表示&#xff1a; 实数部分&#xff1a; 虚数部分&#xff1a; 其中&#xff1a; 代码中参数和Gabor函数参数对应关系 代码实现了Gabor滤波器的实数部分。代码中参数和Gabor函数实数部分参数对应如下&#xff1a; 对应 看上去是不是感觉很容易实现Gabor…

gabor特征 gabor滤波器

gabor特征 Gabor 特征是一种可以用来描述图像纹理信息的特征&#xff0c;Gabor 滤波器的频率和方向与人类的视觉系统类似&#xff0c;特别适合于纹理表示与判别。Gabor 特征主要依靠 Gabor 核在频率域上对信号进行加窗&#xff0c;从而能描述信号的局部频率信息。Gabor 核靠傅…

Log-Gabor Filters

原文转自&#xff1a;http://www.csse.uwa.edu.au/~pk/research/matlabfns/PhaseCongruency/Docs/convexpl.html What Are Log-Gabor Filters and Why Are They Good? Gabor filters are a traditional choice for obtaining localised frequency information. They offer the…

Gabor

出处&#xff1a;http://zhenyulu.cnblogs.com/articles/325968.html 二、Gabor函数 Gabor变换属于加窗傅立叶变换&#xff0c;Gabor函数可以在频域不同尺度、不同方向上提取相关的特征。另外Gabor函数与人眼的生物作用相仿&#xff0c;所以经常用作纹理识别上&#xff0c;并取…

Gabor滤波器与特征提取

一、Gabor滤波器 Gabor滤波器&#xff0c;最主要使用优势体现在对物体纹理特征的提取上。 二维Gabor基函数能够很好地描述哺乳动物初级视觉系统中一对简单视觉神经元的感受野特性。随着小波变换和神经生理学的发展&#xff0c;Gabor变换逐渐演变成二维Gabor小波的形式。Gabor…

【图像处理】Gabor滤波器

Gabor的核函数参考的wiki 使用实数Real的公式计算核函数代码&#xff1a; Mat getGaborFilter(float lambda, float theta, float sigma2,float gamma, float psi 0.0f){if(abs(lambda-0.0f)<1e-6){lambda 1.0f;} float sigma_x sigma2;float sigma_y sigma2/(gamma*gam…

生物特征识别中的Gabor滤波器

Daugman&#xff08;1980&#xff09;提出的2D Gabor滤波器&#xff08;以下简称Gabor滤波器&#xff09;&#xff0c;在纹理分类、纹理分割、生物特征识别中取得了广泛的应用。本文首先简要介绍Gabor滤波器&#xff0c;然后列举它在生物特征识别方面的代表性应用。 2D Gabor滤…