Android技术面试Android部分
一、基础知识
1.Android启动模式
针对android的启动模式,需要了解下Activity栈和taskAffinity等知识。
Standard:系统默认,启动一个就多一个Activity实例
SingleTop:栈顶复用,如果处于栈顶,则生命周期不走onCreate()和onStart(),会调用onNewIntent(),适合推送消息详情页,比如新闻推送详情Activity;
SingleTask:栈内复用,如果存在栈内,则在其上所有Activity全部出栈,使得其位于栈顶,生命周期和SingleTop一样,app首页基本是用这个
SingleInstance:这个是SingleTask加强本,系统会为要启动的Activity单独开一个栈,这个栈里只有它,适用新开Activity和app能独立开的,如系统闹钟。
Intent也需要进一步了解,Action、Data、Category各自的用法和作用,还有常用的
Intent.FLAG_ACTIVITY_SINGLE_TOP
Intent.FLAG_ACTIVITY_NEW_TASK
Intent.FLAG_ACTIVITY_CLEAR_TOP
2.View的绘制流程
ViewRoot
-> performTraversal()
-> performMeasure()
-> performLayout()
-> perfromDraw()
-> View/ViewGroup measure()
-> View/ViewGroup onMeasure()
-> View/ViewGroup layout()
-> View/ViewGroup onLayout()
-> View/ViewGroup draw()
针对View的绘制,还需要了解invalidate方法和requestLayout方法。
invalidate方法,有带4个参数的,和不带参数有什么区别?
requestLayout触发measure和layout,如何实现局部重新测量,避免全局重新测量问题?
3.事件分发机制
-> dispatchTouchEvent()
-> onInterceptTouchEvent()
-> onTouchEvent()
requestDisallowInterceptTouchEvent(boolean)
另外还有onTouchEvent()、onTouchListener、onClickListener的先后顺序等问题。
4.消息分发机制(Handler/Looper机制)
(1).为什么一个线程只有一个Looper、只有一个MessageQueue?
(2).如何获取当前线程的Looper?是怎么实现的?(理解ThreadLocal)
(3).是不是任何线程都可以实例化Handler?有没有什么约束条件?
(4).Looper.loop是一个死循环,拿不到需要处理的Message就会阻塞,那在UI线程中为什么不会导致ANR?
(5).Handler.sendMessageDelayed()怎么实现延迟的?结合Looper.loop()循环中,Message=messageQueue.next()和MessageQueue.enqueueMessage()分析。
5.如何保证Service不被杀死?如何保证进程不被杀死?
答:开启2个Service相互监听,如果有一方被kill掉,另一个捕获到立即启动,以达到service永远都在运行的状态。
6.Android的进程通信机制(Binder/IPC)? 线程(进程间)通信机制有哪些?
答:略。
7.SharedPreference原理?能否跨进程?如何实现?
答:略。
8.bundle的数据结构,如何存储,既然有了Intent.putExtra,为啥还要用bundle。
答:bundle的内部结构其实是Map,传递的数据可以是boolean、byte、int、long、float、double、string等基本类型或它们对应的数组,也可以是对象或对象数组。当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口。
9.asynctask的原理
答:AsyncTask是对Thread和Handler的组合包装。
二、性能优化
1.UI优化
(1)合理地选择RelativeLayout /LinearLayout/FrameLayout。
RelativeLayout会让子View调用2次onMeasure,而且布局相对复杂时,onMeasure相对比较复杂,效率比较低,LinearLayout在weight > 0时也会让子View调用2次onMeasure。
(2)合理地使用<include> <merge> <ViewStub>等布局标签。
(3)减少布局层级,可以通过手机开发者选项 GPU过渡绘制查看,一般控制在4层以内,超过5层就要考虑是否需要重新排版布局。
(4)自定义View时,重写onDraw()方法,不要在该方法中新建对象,否则容易触发GC,导致性能下降。
(5)使用ListView时需要复用contentView,并使用Holder减少findViewById加载View。
(6)去除不必要背景:getWindow().setBackgroundDrawable(null)。
(7)使用TextView的leftDrawable/rightDrawable代替ImageView+TextView布局。
2.内存优化
内存优化主要是为了避免OOM和频繁触发到GC导致性能下降(使用LeakCanary检测内存泄露)。
(1)尽可能的规范编码,不在使用的资源注意回收,例如:Bitmap.recycle(), Cursor.close, inputStream.close()。
(2)大量加载Bitmap时,根据View大小加载Bitmap,合理选择inSampleSize,RGB_565编码方式;以及使用LruCache缓存机制。
(3)使用 静态内部类+WeakReference 代替内部类,如Handler、线程、AsyncTask。
(4)使用线程池管理线程,避免线程的新建。
(5)使用单例持有Context,需要记得释放,或者使用全局上下文。
(6)静态集合对象注意释放。
(7)使用webView时,在Activity的onDestory方法中需要移除和销毁,webView.removeAllViews()和webView.destory() 。
3.响应速度优化
Activity如果5秒之内无法响应屏幕触碰事件和键盘输入事件,就会出现ANR;而BroadcastReceiver如果10秒之内还未执行操作也会出现ANR;Server20秒会出现ANR,为了避免ANR,可以开启子线程执行耗时操作,但是子线程不能更新UI,因此需要Handler消息机制、AsyncTask、IntentService进行线程通信。
备:出现ANR时,adb pull data/anr/tarces.txt 结合log分析。
4.其他性能优化
(1)常量使用static final修饰。
(2)使用SparseArray代替HashMap。SparseArray内部存储是通过两个数组(压缩式稀疏数组),查找是通过二分法查找。HashMap底层是一个Hash表,是数组和链表的集合实现,数据量大时查找遍历元素就会很耗内存。
(3)使用线程池管理线程。
(4)根据循环的性能对比,ArrayList遍历使用常规for循环,LinkedList使用foreach。
(5)不要过度使用枚举,枚举占用内存空间比整型大。
(6)字符串的拼接优先考虑StringBuilder和StringBuffer。
(7)数据库存储是采用批量插入+事务。
5.设计模式
单例模式、观察者模式、适配器模式、工厂模式、MVC/MVP/MVVM
6.数据结构
(1)HashMap、LinkedHashMap、ConcurrentHashMap在用法和原理上的差异。
(2)ArrayList(通过数组实现)和LinkedList(基于双向循环链表的,且头结点中不存放数据)对比,它们均实现于List接口。
(3)平衡二叉树、二叉查找树、红黑树。
(4)Set的原理(hash算法)?常用hash算法(MD4/MD5/SHA-1)?HashSet内部用到了HashMap(底层结构是哈希表)。
三、APP打包
TODO