Android面试题及答案
近期打算换工作,所以收集了一点经典安卓面试题,并附上答案。
1.如何对Android应用进行性能分析
android性能主要是响应速度和UI刷新速度。
(1)函数耗时,可以使用TraceView工具,这是android自带的工具,可用于测量函数耗时的。
(2)UI布局分析。有两块,一块是Hierarchy Viewer可以看到View的布局层次,以及每个View刷新加载的时间,可以很块定位到哪一块layout和view耗时最长。另外一块是通过自定义view来减少view的层次。
2.什么情况下会导致内存泄漏
内存泄漏是个麻烦的问题,什么情况下会发生内存泄漏?
内存泄漏的根本原因:长生命周期的对象持有短生命周期的对象,短周期对象就无法及时释放。
(1)静态集合类引起内存泄漏
主要是hashmap,Vector等,如果是静态集合,这些集合没有及时set null,就会一直持有这些对象
(2)remove方法无法删除set集 Object.hash(firstName, lastName);
经过测试,hashcode修改后,就没有办法remove了。
(3)observer。我们在使用监听器的时候,通常是addxxxlistener,但是当我们不需要的时候,忘记removexxxlistener,就容易内存leak。还有就是广播没有unregisterrecevier.
(4)各种数据链接没有关闭,数据库contentprovider, io, socker,cursor等。
(5)内部类。java中的内部类(匿名内部类),会持有宿主类的强引用this。
所以如果是new Thread这种,后台线程的操作,当线程没有执行没有结束时,activity不会被回收,context的引用,当TextView等等都会持有上下文的引用,如果有static drawable就会导致该内存无法释放。
(6)单例。单例是一个全局的静态对象,当持有某个复制的类A时,A无法被释放,内存leak。
3,如何避免OOM异常
首先需要知道什么是OOM?
当程序需要申请一段“大”内存,但是虚拟机没有办法及时给到,及时做了gc操作以后还是会抛出OutOfMemoryException,即OOM。
Android的OOM怎么样?
为了减少单个APP对整个系统的影响,android为每个app设置了一个内存上限。
public void getMemoryLimited(Activity context)
{
ActivityManager activityManager =(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
System.out.println(activityManager.getMemoryClass());
System.out.println(activityManager.getLargeMemoryClass());
System.out.println(Runtime.getRuntime().maxMemory()/(1024*1024));
}
09-10 10:20:00.477 4153-4153/com.joyfulmath.samples I/System.out: 192
09-10 10:20:00.477 4153-4153/com.joyfulmath.samples I/System.out: 512
09-10 10:20:00.477 4153-4153/com.joyfulmath.samples I/System.out: 192
512M一般情况下,192M就是上限,但是由于某些特殊情况,android允许使用一个更大的RAM。
如何避免OOM
(1)减少内存对象的占用
1.ArrayMap/SparseArray代替hashmap
2.避免在android里面使用Enum
3.减少bitmap的内存占用
- inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。
- decode format:解码格式,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8存在很大差异
4.减少资源图片的大小,过大的图片可以考虑分段加载。
(2)内存对象的重复利用
大多数对象的复用,都是利用对象池的技术
1.listview/gridview/recycleview/contentview的复用
2.inBitmap属性对于内存对象的复用ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,这个方法需要加载大量图片的时候很有用。
3.避免在ondraw方法里面new对象
4.StringBuilder代替+
Android中如何捕获未捕获的异常
关键是实现Theard.UncaughtExceptionHandler,然后再application的onCreate()里面注册。
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static CrashHandler instance = null;
public static synchronized CrashHandler getInstance()
{
if(instance == null)
{
instance = new CrashHandler();
}
return instance;
}
public void init(Context context)
{
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Thread:");
stringBuilder.append(thread.toString());
stringBuilder.append("\t");
stringBuilder.append(ex);
TraceLog.i(stringBuilder.toString());
TraceLog.printCallStatck(ex);
}
}
5.ANR是什么?怎么避免和解决ANR(重要)
ANR–>Application Not Responding,在规定的时间内,没有响应
三种情况:
(1)KeyDiapatchTimeout(5 seconds)主要类型按键或触摸时间在特定时间内无响应
(2)BroadcastTimeout(10 seconds)BroadcastReceiver在特定时间内无法处理完成
(3)ServiceTimeout(20 seconds)小概率类型Service在特定的时间内无法处理完成
为什么会超时:事件没有机会处理或者事件处理超时
怎么避免ANR
ANR的关键是处理超时,所以应该避免在UI线程,BroadcastReceiver还有service主线程中处理复杂的逻辑和计算从而交给work thread操作。
(1)避免在activity里面做耗时操作,oncreate&onresume
(2)避免在onReceiver里面做过多的操作
(3)避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。
(4)尽量使用handler来处理UI thread & workthread的交互。
如何解决ANR
首先定位ANR发生的log:
04-01 13:12:11.572 I/InputDispatcher( 220): Application is not responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}. 5009.8ms since event, 5009.5ms since waitstarted
CPUusage from 4361ms to 699ms ago ----CPU在ANR发生前的使用情况
04-0113:12:15.872 E/ActivityManager( 220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait
04-0113:12:15.872 E/ActivityManager( 220): CPUusage from 3697ms to 4223ms later:-- ANR后CPU的使用量
从log可以看出,cpu在做大量的io操作。
所以可以查看io操作的地方。
当然,也有可能cpu占用不高,那就是 主线程被block住了。
6.Android线程间通信有哪几种方式
(1)共享变量(内存)
(2)管道
(3)handle机制
runOnUiThread(Runnable)
view.post(Runnable)
7.Devik进程,linux进程,线程的区别
Devik进程,每一个android app都会独立占用一个dvm虚拟机,运行在linux系统中,所以dalvik进程和linux进程是可以理解为一个概念。
evik虚拟机是运行在Linux操作系统上的,Linux操作系统并没有纯粹的进程概念,只要两个进程共享一个地址空间,那么就可以认为他们是同一个进程的两个线程。Linux提供了两个fork和clone调用,其中,前者是用来创建进程的,而后者是用来创建线程的。
一般来说虚拟机的进程和线程都是和本地操作系统的进程和线程一一对应的,这样的好处是可以使本地操作系统来调度进程和线程。
每一个安卓应用程序都有一个Devik虚拟机实例。这样做的好处是安卓应用程序之间的进程不会受到影响,也就是说,一个安卓应用程序的进程意外终止,不会影响其他应用程序的进行。
每一个安卓应用程序都是由一个称为Zygote的进程fork出来的,Zygote进程是由init进程启动的,也就是在系统启动的时候启动。Zygote进程在启动的时候会启动虚拟机实例,并且这个虚拟机实例将所有的Java核心库都加载起来。每当Zygote进程需要创建一个安卓应用程序进程的时候,他就通过复制自身来实现,也就是通过fork系统调用来实现。这些被fork出来的安卓应用程序进程,一方面是复制了Zygote进程的虚拟机实例,另一方面是与Zygote进程共享了同一套JAVA核心库这样不紧安卓应用程序创建的很快,而且所以的应用程序共用一套JAVA核心库节省了内存空间。
8.描述一下android的系统架构
从下到上就是:
Android系统从下往上分为Linux内核层(linux kerner),运行库(runtime library),应用程序框架层,应用程序层
linuxkernel:负责硬件的驱动程序、网络、电源、系统安全以及内存管理等功能。
libraries和 androidruntime:libraries:即c/c++函数库部分,大多数都是开放源代码的函数库,例如webkit,该函数库负责 android网页浏览器的运行
applicationframework(应用软件架构),java应用程序开发人员主要是使用该层封装好的api进行快速开发。
applications:该层是java的应用程序层,android内置e-mail、即时通信工具、浏览器、mp3播放 器等处于该层,java开发人员开发的程序也处于该层,而且和内置的应用程序具有平等的位置,可以调用内置的应用程序,也可以替换内置的应用程序。
下层为上层服务,上层需要下层的支持,调用下层的服务,这种严格分层的方式带来的极大的稳定性、灵活性和可扩展性,使得不同层的开发人员可以按照规范专心特定层的开发。
android应用程序使用框架的api并在框架下运行,这就带来了程序开发的高度一致性,另一方面也告诉我们,要想写出优质高效的程序就必须对整个 applicationframework进行非常深入的理解。精通applicationframework,你就可以真正的理解android的设计 和运行机制,也就更能够驾驭整个应用层的开发。
9.android应用对内存是如何限制的?我们应该如何合理使用内存
可以使用activitymanager.getMemoryClass()获取内存限制,关于合理使用内存,在上面如何避免OOM和内存泄漏中已经说明。
10.简述android应用程序结构是哪些
1)main code
2) unit test
3)mianifest
4)res->drawable,drawable-xxhdpi,layout,value,mipmap
mipmap 是一种很早就有的技术了,翻译过来就是纹理映射技术.
google建议只把启动图片放入。
5)lib
6)color
11.请解释一下Android程序运行时权限与文件系统权限的区别
文件的系统权限是由linux系统规定的,只读,读写等。
运行时权限,是对于某个系统上的app的访问权限,允许,拒绝,询问。该功能可以防止非法的程序访问敏感的信息。
12.Framework工作方式及原理,activity是如何生成一个view的,机制是什么?
Framework是android 系统对 linux kernel,lib库等封装,提供WMS,AMS,bind机制,handler-message机制等方式,供app使用。
简单来说framework就是提供app生存的环境。
1)Activity在attch方法的时候,会创建一个phonewindow(window的子类)
2)onCreate中的setContentView方法,会创建DecorView
3)DecorView 的addview方法,会把layout中的布局加载进来。
13.多线程间通信和多线程之间通信有什么不同,分别怎么实现
线程间的通信可以参考第6点。
进程间的通信:bind机制(IPC->AIDL),linux级共享内存,boradcast,
Activity 之间,activity & serview之间的通信,无论他们是否在一个进程内。
14.Android屏幕适配
屏幕适配的方式:xxxdpi, wrap_content,match_parent. 获取屏幕大小,做处理。
dp来适配屏幕,sp来确定字体大小
drawable-xxdpi, values-1280*1920等 这些就是资源的适配。
wrap_content,match_parent, 这些是view的自适应
weight,这是权重的适配。
15,什么是AIDL以及如何使用
Android Interface Definition Language
AIDL是使用bind机制来工作。
参数:
java原生参数
String
parcelable
list & map 元素 需要支持AIDL
16.Handler机制
17.事件分发机制
18.子线程发消息到主线程进行更新UI,出来handler和AsyncTask,还有什么
EventBus,广播,view.post, runinUiThread
但是无论各种花样,本质上就2种:handler机制 + 广播
19。子线程中能不能 new handler?为什么
必须可以。子线程 可以new 一个mainHandler,然后发送消息到UI Thread。
20.Android 中的动画有哪几类,它们的特点和区别是什么
视图动画,或者说补间动画。只是视觉上的一个效果,实际view属性没有变化,性能好,但是支持方式少。
属性动画,通过变化属性来达到动画的效果,性能略差,支持点击等事件。android 3.0
帧动画,通过drawable一帧帧画出来。
Gif动画,原理同上,canvas画出来。
21如何修改 Activity 进入和退出动画
overridePendingTransition
SurfaceView & View 的区别
view的更新必须在UI thread中进行
surfaceview会单独有一个线程做ui的更新。
surfaceview 支持open GL绘制。
未完待续。。。。