Android面试
参考文章
2 assets和res/raw的区别
- assets中的文件资源不会映射到R中,而res中的文件都会映射到R中,所以raw文件夹下的资源都有对应的ID;
- assets可以能有更深的目录结构,而res/raw里面只能有一层目录;
- 资源存取方式不同,assets中利用AssetsManager,而res/raw直接利用getResource(), openRawResource(R.raw.fileName)
3 Serializable 和 Parcelable 的区别
- Serializable 使用 I/O 读写存储在硬盘上,而 Parcelable 是直接在内存中读写。很明显,内存的读写速度通常大于 IO读写,所以在 Android 中传递数据优先选择 Parcelable。
- Serializable 会使用反射,序列化和反序列化过程需要大量 I/O 操作; Parcelable 自已实现封送和解封(marshalled &unmarshalled)操作不需要用反射,数据也存放在Native内存中,效率要快很多。
传递大数据的方式
文件,数据库,静态变量
Context的理解
是运行上下文环境。代码角度看是Application、Activity、Service。
所有Context都是在主线程ActivityThread创建
导致内存泄露:
2 1. 静态资源
2. 单例模式
避免:
- 尽量少用Context对象获取静态变量,静态方法,以及单例对象
- 在引用静态资源,创建静态方法,单例等情况下,使用生命周期更长的Application的Context去创建UI相关的对象,如Dialog,View等。
Activity
-
Activity、View、Window的关系?
Activity -》 PhoneWindow -》DecorView -》 ActionBar&ContentView
DecorView是一个FrameLayout -
Activity1跳转到Activity2,Activity2显示缓慢的原因?
- 在Activity1的
onPause()
有耗时操作; - 在Activity2的
onCreate()
或者onStart()
或onResume()
中有耗时操作;
总结 在Activity2的onResume及之前有耗时操作(以上的4个方法过程,均在Activity2的onResume()
之前执行)
- 在Activity1的
4 Service
- startService和 bindService的区别
- startService: 与调用者无关, 调用者退出, service不会关闭;
生命周期:onCreate-onStartCommand -- onDestroy
- bindService: 与调用者绑定, 调用者关闭, service会关闭 (activity在finish的时候, 会直接调用service进入销毁周期);
生命周期:onCreate-onBind -- onUnbind-onDestroy
- startService: 与调用者无关, 调用者退出, service不会关闭;
- IntentService
- IntentService继承自Service,可用
startService()
启动,也需要在 AndroidManifest.xml 中注册 - 可多次启动同一个IntentService,它们会自一个接一个地排队处理
- 可以执行耗时任务, 在
onHandleIntent()
中执行 - 操作完成时,不用手动停止IntentService,它会自动判定停止, 多次startService, 只会执行一次onDestroy
- IntentService继承自Service,可用
* Handler机制
Handler发送Message到MessageQueue中, Looper从MessageQueue中取出Message,交给Handler的handleMessage方法进行处理
Handler:负责消息的发送和处理
Message:消息对象(类似于链表的一个节点)
MessageQueue:消息队列,用于存放消息对象的数据结构
Looper:消息队列的矗立着,用于轮询消息队列的消息对象
5.1 子线程能否直接new一个Handler?
不能直接new,因为在Handler的构造方法中,会通过Looper.myLooper()获取mLooper对象,子线程中mLooper对象为空,会抛异常。
如果是创建子线程的Handler, 需要三步:
1. Looper.prepare(); //为当前线程准备消息队列
2. Handler handler = new Handler(); // 默认构造方法跟当前线程中的Looper产生关联
3. Looper.loop(); //开启循环取消息
因为子线程的handler需要准备looper,同时要启动Looper.loop(),只有这样handler的机制才能够正常运行。
5.2 一个线程可以有几个Handler,几个Looper,几个MessageQueue对象?
无数个Handler,一个Looper,一个MessageQueue
在Looper.prepare()中,创建了Looper对象,并放入ThreadLocal中,通过ThreadLocal获取Looper对象,ThreadLocal内部维护了一个ThreadLocalMap,其是以当前thread作为key的,所以可以看出一个thread最多只有一个looper对象;在Looper的构造方法中,会创建MessageQueue对象,因为Looper只会构造一个,所以MessageQueue对象只有一个。