Android知识点
0.软引用和弱引用的区别?
软引用是在内存不足是gc才会回收他们,而弱引用则是内存充足时也有可能被回收
软引用可以被用来实现对内存敏感的高速缓存。
java 中对象的引用有4种:强引用StrongReference、软引用sofeReference、弱引用weakReference、虚引用phantomReference
其中phantomReference主要是用来跟踪垃圾回收器的回收活动,而虚引用和软引用、弱引用的区别在于,虚引用必须与引用队列ReferenceQueue联合使用,当gc准备回收对象时,若发现他还有虚引用,就会将该虚引用加入到与之关联的引用队列中。
内存不足是指什么?
Android系统在启动app时都会通过zygote进程启动一个app进程,并拷贝一个dvm然后启动app,app进程会被分配一块固定大小的内存空间,当app占用的空间等于or大于系统分配的空间时,就会出现内存不足和内存溢出的情况,就会触发GC
有两个条件会触发主GC:
- 当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。
- Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报“out of memory”的错误,Java应用将停止。
扩展:
a.Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?
Dalvik虚拟机允许多个instance的存在。实际上android中的每一个app都是运行在自己VM实例之中(沙盒)。每一个VM实例在linux中又是一个单独的进程,所以可以认为是同一个概念。运行在自己的DVM进程之中,不同的app不会相互干扰,且不会因为一个DVM的崩溃导致所有的app进程都崩溃。
集合的泛型和类型擦除?
什么是泛型?
泛型又叫参数化类型,即参数化的类型,或者说将类型当做参数传入到方法或类中。
泛型分为3种:
方法泛型、
public class Test1 {
public <T> void testMethod(T t){
}
}
类泛型、
public class Test<T> {
T field1;
}
接口泛型
public interface Iterable<T> {
}
类型擦除:通过将类型参数的合并,将泛型类型的实例关联到同一份字节码上
asyncTask 原理是啥?他是怎么保证串行执行的?
AsyncTask的本质是对线程池和Handler 的封装
在AsyncTask中有一个实现了executor接口的静态内部类SerialExecutor,在其中包含了ArrayDeque 双向链表,包含了所有要执行的任务,通过先进先出原则保证的串行。还有一个实现了executor的线程池负责执行任务
HashMap的原理
hashMap的数据结构是数组+链表结构。
当要put一个值得时候,会先计算key的hashCode做为数组的index,将包含key,value的对象放入数组中。如果key的hashCode发生了碰撞,即同一index的位置中已经保存了对象了,则在包含key,value对象中在持有一个下一个包含key,value的对象,构成链表。
当要get一个值得时候,先计算key的hashCode从数组取对象,如果该对象中不包含下一个对象,则直接返回,如果包含则使用对象的key进行equals比较,取出key相同的对象,返回。
HashMap中数组初始长度?负载因子?
HashMap中数组初始化长度为16,负载因子为0.75,因此当数组数量大于16*0.75=14就会自动扩容一倍变为32
在activity中new Handler 为什么会导致内存泄漏?
因为activity在销毁时,Handler对象中还存在未执行完的任务,会持有activity对象,导致activity 不能被gc回收
Handler原理:
准备条件:在主线程中先new Loop对象,loop对象中包含了一个链表MessageQueue并对MQ不断的循环,取出其中的Message对象,Message对象持有了一个Handler对象,循环时会调用Handler的handlerMessage()。
开始使用:在主线程中new handler对象H,对象中包含了handlerMessage()方法用来接收处理子线程发送过来的数据。Handler对象中会get并持有主线程的loop对象。当在工作子线程需要更新UI时,在工作线程中通过持有主线程中创建的H对象,调用sendMessage(new Message()),会通过H持有的loop对象,向包含在loop中的MQ中存入消息,以便loop循环调用,调用后执行handler的HandlerMessage();
详情见图:
parcelable 和serializable的区别
区别 | Serializable | Parcelable |
所属API | JAVA API | Android SDK API |
原理 | 通过ObjectInputStrem和ObjectOutputStream类进行操作,序列化和反序列化过程需要大量的I/O操作 | 通过将对象传化成Parcel对象,进行操作,序列化和反序列化过程不需要大量的I/O操作 |
开销 | 开销大 | 开销小 |
效率 | 低 | 很高 |
使用场景 | 序列化到本地或者通过网络传输 | 内存序列化,app运行时存到Intent or Bundle中 进行数据传递。 |
ListView 优化:
a.使用CovertView:在getView()中发现CoverView 不为null,则直接返回这个CovertView 不在新建view
b.使用ViewHolder:在adapter中建一个内部类ViewHolder ,将UI中需要更新的View控件做为属性。在adapter的getView()中将Inflate的view控件赋值给ViewHodler,并将其setTag到covertView中,
当下次在getView()时,发现covertView不为null,则直接取其tag中的ViewHolder使用,省了inflate的时间。
c.异步加载:将耗时操作放到异步线程中执行
例如从网络加载图片
d.对图片进行内存缓存LruCach,和文件缓存
e.简化itemView的布局层次
f.减少getView中的逻辑判断
g.控件更新前对比数据是否变化,更新UI的消耗大于对比的消耗
h.使用自定义布局
i.使用 RecyclerView
k.禁用AnimationCache和ScrollingCache
l. Adapter 的 hasStableIds() 返回 false 配合 getItemId()实现局部刷新,减少getView()的调用