安卓面试题 进阶篇

ThreadLocal作用以及原理?

ThreadLocal用于实现在不同的线程中存储线程私有数据的类。在多线程的环境中,当多个线程需要对某个变量进行频繁操作,同时各个线程间不需要同步。此时,各个子线程只需要对存储在当前线程中的变量的拷贝进行操作即可,程序的运行效率会很高,即所谓的空间换时间。

原理:在当前线程中调用get方法时,通过ThreadLocal的initialValue方法创建当前线程的一个本地数据拷贝,将此拷贝添加到当前线程本地数据的table数组当中;或者在调用set方法时,将当前线程的本地数据存储到当前线程的table数组中.当前线程通过调用ThreadLocal对象的get方法即得到当前线程本地数据对象。

请简要描述一下View事件传递分发机制

事件的传递顺序 Activity -> Window -> View。

事件分发的关键函数:
dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。

dispatchTouchEvent:用于事件的分发,如果事件传递到View层级,则一定会调用此函数。函数的返回结果受当前View的onTouchEvent方法和处于下一层级View的dispatchTouchEvent方法影响。
onInterceptTouchEvent:返回结果表示是否拦截此事件
onTouchEvent:用于处理事件,如果View决定拦截事件则在该函数中进行事件处理。

事件分发中的onTouch和onTouchEvent有什么区别,又该如何使用?

onTouchListener的onTouch方法优先级比onTouchEvent高,会先触发。
若onTouch方法返回false则会接着触发onTouchEvent,反之onTouchEvent方法不会被调用。

View和ViewGroup分别有哪些事件分发相关的回调方法

dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。

View绘制流程

onMeasure:测量视图的大小,从顶层父View到子View递归调用measure()方法,measure()调用onMeasure()方法,onMeasure()方法完成绘制工作。
onLayout:确定视图的位置,从顶层父View到子View递归调用layout()方法,父View将上一步measure()方法得到的子View的布局大小和布局参数,将子View放在合适的位置上。
onDraw:绘制最终的视图,首先ViewRoot创建一个Canvas对象,然后调用onDraw()方法进行绘制。onDraw()方法的绘制流程为:
绘制视图背景-> 绘制画布的图层->绘制View内容->绘制子视图。

如何取消AsyncTask?

调用cancel方法,传递信号量。同时,在doInBackground中检测当前状态:当状态是cancel状态,则立刻跳出循环。

为什么不能在子线程更新UI?

安卓系统的UI控件并非线程安全的,如果多线程并发访问同一个UI控件时会引发UI控件状态的混乱。

ANR产生的原因是什么?
ANR的全称是application not responding,意思就是程序未响应。
产生原因:

1.主线程执行了耗时操作,在一定时间内没有响应操作。比如数据库操作或网络编程。
2.其他进程(就是其他程序)占用CPU导致本进程得不到CPU时间片,比如其他进程的频繁读写操作可能会导致这个问题。

ANR定位和修正
可以通过查看/data/anr/traces.txt查看ANR信息。根据日志文件的信息提示修改代码。

OOM是什么?

OOM,全称“Out Of
Memory”,翻译为“内存用尽”当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出OOM。

什么情况导致OOM?
OOM常见情况:

1)Acitivity没有对栈进行管理,如果开启过多,就容易造成内存溢出 2)加载大的图片或者同时数量过多的图片的时候
3)程序存在内存泄漏问题,导致系统可用内存越来越小。 4)递归次数过多,也会导致内存溢出.
5)频繁的内存抖动,也会造成OOM异常的发生,大量小的对象被频繁的创建,导致内存碎片,从而当需要分配内存的时候,虽然总体上还有内存分配,但是由于这些内存不是连续的,导致无法分配,系统就直接返回OOM了

有什么解决方法可以避免OOM?

1)减小对象的内存占用,避免OOM的第一步就是要尽量减少新分配出来的对象占用内存的大小,尽量使用更加轻量的对象。
2)内存对象的重复利用,大多数对象的复用,最终实施的方案都是利用对象池技术,要么是在编写代码时显式地在程序里创建对象池,然后处理好复用的实现逻辑。要么就是利用系统框架既有的某些复用特性,减少对象的重复创建,从而降低内存的分配与回收。
3)避免对象的内存泄露,内存对象的泄漏,会导致一些不再使用的对象无法及时释放,这样一方面占用了宝贵的内存空间,很容易导致后续需要分
配内存的时候,空闲空间不足而出现OOM。 4)内存使用策略优化。

OOM是否可以try catch?为什么?

可以。在某些情况下,我们需要事先评估那些可能发生OOM的代码,对于这些可能发生OOM的代码,加入catch机制,可以考虑在catch里面尝试一次降级的内存分配操作。

内存泄漏是什么?

内存泄漏(Memory
Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

什么情况导致内存泄漏?
常见情况:
1)单例造成的内存泄漏

由於单例的静态特性使得其生命周期和应用的生命周期一样长,如果一个对象已经不再需要使用了,而单例对象还持有该对象的引用,就会使得该对象不能被正常回收,从而导致了内存泄漏。

2)非静态内部类创建静态实例造成的内存泄漏

3)Handler造成的内存泄漏

当Activity结束时,未处理的消息持有handler的引用,而handler又持有它所属的外部类也就是MainActivity的引用。这条引用关系会一直保持直到消息得到处理,这样阻止了MainActivity被垃圾回收器回收,从而造成了内存泄漏。

4)线程造成的内存泄漏

若线程持有Activity的引用,且线程处于后台执行状态,当Activity销毁但线程仍然存活且持有Activity的引用,则会引起内存泄漏。

5)资源未关闭造成的内存泄漏

对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄漏。

6)使用ListView时造成的内存泄漏

初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的View对象,同时ListView会将这些View对象缓存起来。当向上滚动ListView时,原先位于最上面的Item的View对象会被回收,然后被用来构造新出现在下面的Item。这个构造过程就是由getView()方法完成的,getView()的第二个形参convertView就是被缓存起来的Item的View对象(初始化时缓存中没有View对象则convertView是null)。构造Adapter时,没有使用缓存的convertView。

7)集合容器中的内存泄露

我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。

8)WebView造成的泄露

当我们不要使用WebView对象时,应该调用它的destory()函数来销毁它,并释放其占用的内存,否则其长期占用的内存也不能被回收,从而造成内存泄露。

如何防止内存泄漏?

1)在涉及使用Context时,对于生命周期比Activity长的对象应该使用Application的Context。凡是使用Context优先考虑Application的Context,当然它并不是万能的,对于有些地方则必须使用Activity的Context。
2)对于需要在静态内部类中使用非静态外部成员变量(例如:Context、View
),可以在静态内部类中使用弱引用来引用外部类的变量来避免内存泄漏。
3)对于不再需要使用的对象,显示的将其赋值为null,比如使用完Bitmap后先调用recycle(),再赋为null。
4)保持对对象生命周期的敏感,特别注意单例、静态对象、全局性集合等的生命周期。
5)对于生命周期比Activity长的内部类对象,并且内部类中使用了外部类的成员变量,可以采用以下方式避免内存泄漏: ①
将内部类改为静态内部类 ② 静态内部类中使用弱引用来引用外部类的成员变量

内存泄漏和内存溢出区别?

内存泄漏:主要是因为程序存在BUG 导致内存没有释放 。 内存溢出:是指内存不够用了,导致不够用的原因很多,内存泄漏是导致内存溢出原因一种。

LruCache默认缓存大小

LruCache默认缓存大小是当前操作系统分配给该进程的内存的1/8。

广播是否可以请求网络?

从4.0 开始所有的网络请求都需要在线程中,广播请求网络同理 开启线程在线程中请求网络

广播引起anr的时间限制是多少?

Activity----->5秒
BroadcastReceiver----->10秒
Service----->20秒

Android为什么引入Parcelable?

Java提供了Serializable接口方式实现序列化,但这种方式效率较低。因此,安卓提供Parcelable接口以实现更加高效的序列化方式。

简述一下NDK

NDK(Native Development Kit)是Android的一个工具开发包。
NDK的目的是快速开发C、C++的动态库,并自动将so和应用一起打包成APK。即可通过NDK在Android中使用JNI与本地代码(如C、C++)交互。

JNI是什么?

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。

如何在jni中注册native函数,有几种注册方式?

静态注册 动态注册

JNI调用Java方法

JNI调用Java方法:首先通过类名找到类,然后根据方法名找到方法的id,然后调用该方法。

进程间通信的方式?

安卓系统下进程间通信主要有以下几种方式:

1)Bundle
2)文件共享
3)AIDL
4)Messager
5)ContentProvider
6)Socket

简述AIDL?

AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言,设计AIDL目的是为了实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信。

Android进程分类?

1.前台进程(foreground process):需要用户当前正在进行的操作。一般满足以下条件:

1)屏幕顶层运行Activity(处于onResume()状态),用户正与之交互 2)有BroadcastReceiver正在执行代码
3)有Service在其回调方法(onCreate()、onStart()、onDestroy())中正在执行代码

这种进程较少,一般来作为最后的手段来回收内存

2.可视进程(visible process):做用户当前意识到的工作。一般满足以下条件:

1)屏幕上显示Activity,但不可操作(处于onPause()状态) 。
2)有service通过调用Service.startForeground(),作为一个前台服务运行 。
3)含有用户意识到的特定的服务,如动态壁纸、输入法等 。

这些进程很重要,一般不会杀死,除非这样做可以使得所有前台进程存活。

3.服务进程(service process):含有以startService()方法启动的service。虽然该进程用户不直接可见,但是它们一般做一些用户关注的事情(如数据的上传与下载)。
这些进程一般不会杀死,除非系统内存不足以保持前台进程和可视进程的运行。对于长时间运行的service(如30分钟以上),系统会考虑将之降级为缓存进程,避免长时间运行导致内存泄漏或其他问题,占用过多RAM以至于系统无法分配充足资源给缓存进程。

4.缓存/后台进程(cached/background process):一般来说包含以下条件:

1)包含多个Activity实例,但是都不可见(处于onStop()且已返回)。 系统如有内存需要,可随意杀死。

喜欢的话请帮忙转发一下能让更多有需要的人看到吧,有些技术上的问题大家可以多探讨一下。

更多面试资料或其他Android资料可在QQ群里获取:936903570。有加群的朋友请记得备注上CSDN,谢谢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章