Android面试题集锦二

本文深入解析Android应用中导致ANR(Application Not Responding)问题的原因及解决策略,包括优化耗时操作的执行方式,合理管理Context引用,避免在Adapter构造时的内存泄露,以及正确处理Handler通信中的内存泄漏问题,确保应用响应性和用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是 ANR 问题?为什么会引起 ANR 问题?
1.ANR定义:在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。所以一个流畅的合理的应用程序中不能出现anr,而让用户每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样系统不会显示ANR给用户。
2.什么会引起ANR问题
在Android里,应用程序的响应性是由Activity Manager和WindowManager系统服务监视的 。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR:
a.在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)
b.BroadcastReceiver在10秒内没有执行完毕
造成以上两点的原因有很多,比如在主线程中做了非常耗时的操作,比如说是下载,io异常等。

潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。然而,不是说你的主线程阻塞在那里等待子线程的完成——也不是调用 Thread.wait()或是Thread.sleep()。替代的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。

3.如何避免ANR
a、运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。(可以采用重新开启子线程的方式,然后使用Handler+Message的方式做一些操作,比如更新主线程中的ui等)

b、应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为 BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个 Service。

c、避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广 播时需要向用户展示什么,你应该使用Notification Manager来实现。
2.OOM是怎么引起的?怎么尽量避免 OOM 问题的出现
如果应用程序在消耗光了所有的可用堆空间(16M到48M),那么再试图在堆上分配新对象时就会引起OOM(OutOf Memory Error)异常,此时应用程序就会崩溃退出。
OOM引起的原因:
1.应用加载大图时,没有对图片进行处理就放入手机,会导致OOM。通过设置BitmapFactory.Optiions的inJustDecodeBounds属性为true,这样的话不会加载图片到内存中,但是会将图片的width和height属性读取出来,然后获取手机屏幕的尺寸,做出合适的缩放然后再加载进来。
2.持有Context引用造成的泄漏。在Android应用程序中,很多操作都用到了Context对象,但是大多数都是用来加载和访问资源的。这就是为什么所有的显示控件都需要一个Context对象作为构造方法的参数。在Android应用程序中通常可以使用两种Context对象:Activity和Application。当类或方法需要Context对象的时候常见的作法是使用第一个作为Context参数。但这就意味着View对象对整个activity保持引用,因此也就保持对activity内的所有东西的引用,也就是整个View结构和它所有的资源都无法被及时的回收,而且对activity的长期引用是比较隐蔽的。
避免Context泄漏应该注意的问题: 尽量使用Application这种Context类型,注意对Context的引用不要超过它本身的生命周期,慎重的对Context使用“static”关键字,Context里如果有线程,一定要在onDestroy()里及时停掉。
3.构造Adapter时,没有使用缓存的convertView。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list
item的view对象会被回收,然后被用来构造新出现的最下面的list
item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View,convertView就是被缓存起来的list,item的view对象(初始化时缓存中没有view对象则convertView是null)。由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费时间,也造成内存垃圾,给垃圾回收增加压力,如果垃圾回收来不及的话,虚拟机将不得不给该应用进程分配更多的内存,造成不必要的内存开支。
4.static关键字的滥用。当类的成员变量声明成static后,它是属于类的而不是属于对象的,如果我们将很大的资源对象(Bitmap,context等)声明成static,那么这些资源不会随着对象的回收而回收,会一直存在,所以在使用static关键字定义成员变量的时候要慎重。
5.线程之间通过Handler通信引起的内存泄漏,在通过Handler进行通信时如果不注意,也很有可能引起内存泄漏。在sendMessage完成之后显示的将msg成员变量置为null,并且在退出整个应用程序之前,将handler置为null。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值