Android-常见面试题

来源:互联网 发布:知柏地黄丸女童能吃吗 编辑:程序博客网 时间:2024/06/12 01:42

求职过程中,面试时必不可少的一个环节,能不能拿到offer,面试中的回答是非常关键。在Android求职中,面试也是必不可少的一个环节,接下来整理一下本人面试过程中常常遇到的Android问题:

1. Android四大组件是什么?作用分别是什么?

  • Activity:Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很多持久化的事情,妥善管理生命周期及一些跳转逻辑
  • Service:后台服务于Activity,封装有一个完整的功能实现,接受上层指令,完成相关的事物,定义好需要Intent提供同步或异步的接口
  • ContentProvider:Android提供第三方应用数据访问方案,可以派生ContentProvider类,对外提供数据,可以像数据库一样选择排序,屏蔽内存数据的存储细节,大大简化上层应用,为数据的整合提供了更方便的途径
  • BroadCastReceiver:接受一种或多种Intent作触发事件,接收相关处理,做一些简单处理,转化成一条Notification,统一了Android的事件广播模型

2. Activity的生命周期

onCreate()onStart()onResume()onPause()onStop()onDestory()onRestart()

3. Android内存回收机制

  • 退出不关闭:Android应用程序退出时,系统并不清理其所占用的内存,Linux内核进程也相应的继续存在,这就是所谓的“退出不关闭”
  • 默认的回收机制:当系统内存不足时,系统将激活内存回收过程
  • 回收优先级:空进程-后台进程-服务进程-可见进程-前台进程
  • 触发内存回收的阈值:进行内存调度有一个阈值,只有低于这个阈值时,系统才会按一个列表关闭用户不需要的东西
  • Home键与返回键:home用于多任务切换,返回键用于退出程序。按Home退出时,程序保留状态为后台进程,按返回退出时,程序保留为空进程

4. Android内存优化

  • 使用SparseArray,SparseBooleanArray代替HaspMap:HaspMap是内存低效的,因为每一个Map就需要一个Entry,每个元素将多占8byte内存(多了next和hash两个成员变量)
  • 使用IntentService代替Service:Service默认在UI线程中执行,而IntentService的onHandleIntent()方法在后台执行。Service如果没有手动Stop会一直存在,而IntentService在执行完后会自动退出
  • 尽量避免使用Enum:因为枚举相对于静态常量来说需要2倍甚至更多的内存
  • 使用混淆器移除不必要的代码
  • 不要因为一两个特性使用大体积库
  • 需要频繁修改的字符串使用StringBuilder和StringBuffer代替
  • 对于常量请使用static final:减少类生成时,初始化方法调用时对常量的存储
  • 对象在不用的时候最好设置为null

5. 什么情况下会导致内存泄漏

  • 静态集合类引起内存泄漏:主要是HashMap,Vector等,如果这些静态集合类位set null会一直持有这些对象
  • Observer未移除监听:当我们是有监听器时,往往是addxxxListener,却总是忘记在不需要的时候removexxxListener这样就容易导致内存泄漏。广播未调用unregisterrecevier方法
  • 各种数据连接未关闭:ContentProvider、IO、socket、Cursor等
  • 内部类:Java中的内部类会持有宿主类的this

6. 如何避免OOM

  • ArrayMap/SpareArray代替HaspMap
  • 避免在Android中使用枚举
  • 减少Bitmap对内存的占用
  • 减小资源图片的大小,对于过大图片考虑分段加载
  • ListView/GridView/RecyclerView 对ContentView的复用
  • 避免在onDraw方法中创建对象
  • StringBuilder代替+

7. 年轻代,年老代,持久代

  • 年轻代:分为三个区,一个Eden区,两个Survivor区。大部分的对象都在Eden区生成,当Eden区满时,还存活的对象将会被复制到其中一个Survivor区,当这个Survivor满时,还存活的对象将会被复制到另一个Survivor区,当这个Survivor区也满时,从第一个Survivor区复制过来的并且还存活的对象将会被复制到”年老区”
  • 年老代:年老代存放从年轻代复制过来并且还存活的对象。一般存储生命周期较长的对象
  • 持久代:用于存储静态文件,持久代对于内存回收并没有显著的影响,但是一些应用可能动态生成或调用一些class,这是需要设置一个较大的持久代空间来存放这些新增的类

8. 如何判定垃圾对象

  • 引用计数器算法:给对象添加一个引用计数器,当一个地方引用它时,计数器值加1,引用失效时,计数器值减1,当任何时候计数器值都为0时,就判定这个对象是不可能再被使用。弊端:无法解决对象之间的相互引用问题
  • 根搜索算法:通过一系列名为“GC Roots”的对象作为起始点,从这个节点开始往下搜索,搜索所走过的路称为引用链,当一个对象没有任何引用链相连时,就证明这个对象是不可能被使用的

9. 垃圾回收算法

  • 标记-清除算法:首先标记出需要回收的对象,在标记完成后统一回收掉所有被标记的对象,被标记的过程就是根搜索算法。弊端:效率不高,并且会产生大量内存碎片
  • 复制算法:较适用于年轻代。复制算法是根据标记-清除算法的缺点,在其基础上进行改进的。原理:将可用的内存容量分为大小等同的两块,当其中一块用完了,就将还存活的对象复制到另一块,在将那块容量一次性清理掉。优点:简单,高效,无需考虑内存碎片的出现。确定:将一个次性可用的内存容量缩小到了一半
  • 标记-整理算法:较适用于年老代。因为年老代的生命周期长,存活率高,如果使用大量的复制算法,效率将会变低,所以年老代一般使用其他算法。原理:标记过程与标记-清除算法的标记过程一样,只是对垃圾对象的处理有所不同,它不是直接将垃圾对象回收掉,而是将所有对象都向一端移动,然后清理端边界以外的内存

10.ANR的产生与避免

应用程序无响应,原因有可能是在主线程中做了耗时操作,例如下载,IO异常等。如何避免:
- 在主线程中尽可能的少做事情,耗时操作另开子线程操作
- 用Handler+Message的方式来更新主线程的UI

11. Handler的消息机制

Android提供了Handler与Looper来满足线程之间的通信。Handler先进先出原则,Looper来管理特定线程之间对象的消息交互
- Looper:一个线程会产生一个Looper对象,它用来管理此线程的MessageQueue
- Handler:你可以构建一个Handler对象来与Looper沟通,以便push新的消息到MessageQueue,或获得Looper从MessageQueue中所取得的消息
- MessageQueue:用来存放线程放入的消息

12. Android开发中常见的设计模式

  • 单例模式
  • Build模式(例:AlertDialog)
  • 观察者模式(一些常见的点击事件)
  • 原型模式:implements Cloneable,实现clone方法,实现clone方法的拷贝逻辑。对对象内容的拷贝,生成新的对象
  • 策略模式(例:属性动画中的插值器)

13. 单例模式的写法

  • 懒汉式(线程不安全)
public class A{    private static A instance;    private A(){}    public static A getInstance(){        if(instance == null){            instance = new A();        }        return instance;    }}
  • 懒汉式(线程安全)
public class A{    private static A instance;    private A(){}    public static synchronized A getInstance(){        if(instance == null){            instance = new A();        }        return instance;    }}
  • 饿汉式
public class A{    private static A instance = new A();    private A(){}    public static A getInstance(){        return instance;    }}
  • 饿汉式(变种)
public class A{    private A instance = null;    static{        instance = new A();    }    private A(){}    public static A getInstance(){        return instance;    }}
  • 双重校验
public class A{    private static A instance = null;    private A(){}    public static A getInstance(){        if(instance == null){            synchronized(A.class){                if(instance == null){                    instance = new A();                }            }        }        return instance;    }}

14.单例模式的优缺点

优点:
- 提供了唯一的受控访问
- 由于系统内存中只存在一个对象,因此可以节约系统资源。对于那些需要频繁创建和销毁的对象,单例模式无疑能提高系统的性能
- 允许可变数目的实例

缺点:
- 因为单例模式中没有抽象层,因此单例类的拓展有很大的困难
- 单例类的职责过重,一定程度上违背了”单一职责”原则
- 滥用单例将会带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能为导致共享连接池对象的程序过多而导致连接池溢出。单例类长时间不适用,系统会认为是垃圾而被回收,将会导致对象状态的丢失。

15. Service的生命周期

Service有两种启动方式,启动方式不同,生命周期也不同
- startService:onCreate()-onStartCommand()-onDestory()
- bindService:onCreate()-onBind()-onUnBind()-onDestory()

16. 广播的注册方式

  • 静态注册:在AndroidManifest.xml中注册,Android不能自动销毁广播接收器,即程序关闭时,还会继续接收广播,消耗资源大
  • 动态注册:在代码中调用registerReceiver方法注册,需要手动调用unregisterReceiver方法注销,否则将会内存泄漏

17. 如何防止Service被杀死

  • 在startCommand方法中修改flags的值为START_STICKY或START_READELIVER_INTENT
  • 在onDestory方法中重启Service
  • 创建一个广播,在onReceiver中启动Service

18. 对多线程的理解

在Android中常常需要做一些耗时操作,这些操作不能再主线程中执行,否则将会导致程序无响应,所以我们需要开启子线程来处理这些事物。\
优点:
- 可以将占据时间长的任务,放大后台中执行
- 程序运行效率将会更高
- 无需夸进程边界
- 程序逻辑和控制方式简单

缺点:
- 线程之间的同步和枷锁比较麻烦
- 一个线程的崩溃将可能影响整个程序的稳定性
- 到达一定线程数后,即使增加CPU也无法提高性能(如:Windows Server 2003)

19. TCP与UDP的区别

TCP:TCP是基于连接的协议,也就是说,在正式首发数据之前,必须和对方建立可靠的连接\
UDP:UDP是面向非连接的协议,它不予对方建立连接,而是直接把数据包发送过去\
差别
- TCP面向连接,传输可靠,应用于传输大量数据,数度慢
- UDP面向非连接,传输不可靠,应用于传输少量数据,速度快

20. Activity的启动模式

  • standard:默认模式,在此模式下,默认会创建一个实例。例:A、B、C三个Activity启动顺序为:A-B-C-C,按返回键退出顺序为:C-C-B-A
  • singleTop:可以有多个实例,处于栈顶的Activity中启动自己将不会产生新的实例。例:A、B、C三个Activy,C设置为singleTop,按A-B-C-C顺序启动时,按返回键退出顺序为:C-B-A
  • singleTask:只有一个实例。若一个Activity处于栈中,在当前Task将不会产生新的实例。例:A、B、C三个Activy,B设置为singleTask,按A-B-C-B顺序启动时,按返回键退出顺序为:B-A
  • singleInstance:只有一个实例,并且实例独立运行在一个task中。例:A、B、C三个Activy,B设置为singleInstance,按A-B-C-B顺序启动时,按返回键退出顺序为:B-C-A

21.手机竖屏切换至横屏时,生命周期是否会变化,将怎样变化

  • 默认情况下,onPause-onStop-onDestory-onCreate-onStart-onResume
  • 在AndroidManifest.xml设置:android:configChanges=”orientation|screenSize”时,生命周期将不会变化。api小鱼13时,应为”orientation|keyboardHidden”

22.StringBuffer与StringBuilder的区别

  • StringBuilder:字符串变量,线程非安全的,适用于单线程操作字符串缓冲区下操作大量字符串,执行速度大于StringBuffer
  • StringBuffer:字符串变量,线程安全的,适用于多线程操作字符串缓冲区下操作大量字符串,执行速度慢于StringBuilfer

23.ListView的优化

  • convertView重用
  • 在判断convertView中实例化
  • 数据过多,分页加载

24.冒泡排序的经典算法

从小到大排序:

int nums[] = {5,7,3,2,9};int temp;for(int i = 0; i < nums.length; i++){    for(int j = i + 1; j < nums.length; j++){        if(nums[i] > nums[j]){            temp = nums[i];            nums[i] = nums[j];            nums[j] = temp;        }    }}

25.什么是Context

Context字面意思为上下文,也可以叫做场景,是用户与操作系统交互的一个过程,比如打电话,场景包括显示的界面,以及隐藏在背后的数据

26.什么是Fragment,Fragment的生命周期

Fragment是在嵌入在活动当中的UI片段,它能让程序更加合理和充分利用大屏幕的空间。生命周期:onAttach、onCreate、onCreateView、onActivityCreated、onStart、onResume、onPause、onStop、onDestoryView、onDestory、onDetach

原创粉丝点击