Android面试题大全

1、java面试题(基础+进阶)(必须)
1)、java中==和equals和hashCode的区别
==是运算符,用来比较两个值、两个对象的内存地址是否相等;
equals是Object类的方法,默认状况下比较两个对象是不是同一个对象,内部实现是经过“==”来实现的。
若是想比较两个对象的其余内容,则能够经过重写equals方法,
hashCoed也是Object类里面的方法,返回值是一个对象的哈希码,同一个对象哈希码必定相等,但不一样对象哈希码也有可能相等。
一、若是两个对象equals,Java运行时环境会认为他们的hashcode必定相等。 
二、若是两个对象不equals,他们的hashcode有可能相等。 
三、若是两个对象hashcode相等,他们不必定equals。 
四、若是两个对象hashcode不相等,他们必定不equals。html

2)、int、char、long各占多少字节数(笔试题多出现)
Int:4字节 chat:2字节 long\double:8字节java

3)、int与integer的区别 (笔试)
一、Integer是int的包装类,int则是java的一种基本数据类型 
二、Integer变量必须实例化后才能使用,而int变量不须要 
三、Integer实际是对象的引用,当new一个Integer时,其实是生成一个指针指向此对象;而int则是直接存储数据值 
四、Integer的默认值是null,int的默认值是0android

4)、谈谈对java多态的理解
多态是指:父类引用指向子类对象,在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。(同一消息能够根据发送对象的不一样而采用多种不一样的行为方式。程序员

多态的做用:消除类型之间的耦合关系。web

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。面试

实现多态的三要素:继承,重写,父类引用指向子类对象(即,声明是父类,实际指向的是子类的一个对象)算法

5)、String、StringBuffer、StringBuilder区别
一、三者在执行速度上:StringBuilder > StringBuffer > String (因为String是常量,不可改变,拼接时会从新建立新的对象)。
二、StringBuffer是线程安全的,StringBuilder是线程不安全的。(因为StringBuffer有缓冲区)数据库

6)、什么是内部类?内部类的做用
内部类:将一个类定义在另外一个类里面或者一个方法里面,这样的类称为内部类。
做用:1.每一个内部类都能独立的继承一个接口的实现,因此不管外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,   
2.方便将存在必定逻辑关系的类组织在一块儿,又能够对外界隐藏。   
3.方便编写事件驱动程序   
4.方便编写线程代码设计模式

7)、抽象类和接口区别
相同:
一、都能被继承
二、继承的类都必须将未实现的函数实现
三、只关注方法的定义,不关注方法的实现
差别:
一、一个子类能够继承多个接口,可是只能继承一个父类
二、抽象类在对象中只能表示一种对象,接口能够被不少对象继承数组

8)、抽象类与接口的应用场景
若是你拥有一些方法而且想让它们中的一些有默认实现,那么使用抽象类吧。
若是你想实现多重继承,那么你必须使用接口。因为Java不支持多继承,子类不可以继承多个类,但能够实现多个接口。所以你就能够使用接口来解决它。
若是基本功能在不断改变,那么就须要使用抽象类。若是不断改变基本功能而且使用接口,那么就须要改变全部实现了该接口的类。

9)、抽象类是否能够没有方法和属性?
抽象类专用于派生出子类,子类必须实现抽象类所声明的抽象方法,不然,子类还是抽象类。
包含抽象方法的类必定是抽象类,但抽象类中的方法不必定是抽象方法。
抽象类中能够没有抽象方法,但有抽象方法的必定是抽象类。因此,java中 抽象类里面能够没有抽象方法。 抽象类的做用在于子类对其的继承和实现,也就是多态;而没有抽象方法的抽象类的存在价值在于:实例化了没有意义,由于类已经定义好了,不能改变其中的方法体,可是实例化出来的对象却知足不了要求,只有继承并重写了他的子类才能知足要求。因此才把它定义为没有抽象方法的抽象类

10)、泛型中extends和super的区别
一、< extends T>限定参数类型的上界:参数类型必须是T或T的子类型
限定参数类型的下界:参数类型必须是T或T的超类型
二、 只能用于方法返回,告诉编译器此返参的类型的最小继承边界为T,T和T的父类都能接收,可是入参类型没法肯定,只能接受null的传入
只能用于限定方法入参,告诉编译器入参只能是T或其子类型,而返参只能用Object类接收既不能用于入参也不能用于返参

11)、父类的静态方法可否被子类重写
不能,父类的静态方法可以被子类继承,可是不可以被子类重写,即便子类中的静态方法与父类中的静态方法彻底同样,也是两个彻底不一样的方法。

进程和线程的区别(问的蛮多的,回答的时候用口语说出来,不要背书)
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。
一个进程内可拥有多个线程,进程可开启进程,也可开启线程。
一个线程只能属于一个进程,线程可直接使用同进程的资源,线程依赖于进程而存在。

12)、final,finally,finalize的区别
final:修饰类、成员变量和成员方法,类不可被继承,成员变量不可变,成员方法不可重写
finally:与try...catch...共同使用,确保不管是否出现异常都能被调用到
finalize:类的方法,垃圾回收以前会调用此方法,子类能够重写finalize()方法实现对资源的回收

13)、Serializable 和Parcelable 的区别
Serializable Java 序列化接口 在硬盘上读写 读写过程当中有大量临时变量的生成,内部执行大量的i/o操做,效率很低。
Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中

14)、静态属性和静态方法是否能够被继承?是否能够被重写?以及缘由?
可继承 不可重写 而是被隐藏
若是子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"。若是你想要调用父类的静态方法和属性,直接经过父类名.方法或变量名完成。

15)、成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用
java中内部类主要分为成员内部类、局部内部类(嵌套在方法和做用域内)、匿名内部类(没构造方法)、静态内部类(static修饰的类,不能使用任何外围类的非static成员变量和方法, 不依赖外围类)
使用内部类最吸引人的缘由是:每一个内部类都能独立地继承一个(接口的)实现,因此不管外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
由于Java不支持多继承,支持实现多个接口。但有时候会存在一些使用接口很难解决的问题,这个时候咱们能够利用内部类提供的、能够继承多个具体的或者抽象的类的能力来解决这些程序设计问题。能够这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

16)、string 转换成 integer的方式及原理
String —>integer Intrger.parseInt(string);
Integer—> string Integer.toString();
原理:
parseInt(String s)--内部调用parseInt(s,10)(默认为10进制)
正常判断null,进制范围,length等
判断第一个字符是不是符号位
循环遍历肯定每一个字符的十进制值
经过*= 和-= 进行计算拼接
判断是否为负值 返回结果。

17)、哪些状况下的对象会被垃圾回收机制处理掉?
1.全部实例都没有活动线程访问。
2.没有被其余任何实例访问的循环引用实例。
3.Java 中有不一样的引用类型。判断实例是否符合垃圾收集的条件都依赖于它的引用类型。
18)、要判断怎样的对象是没用的对象。这里有2种方法:
1.采用标记计数的方法:
给内存中的对象给打上标记,对象被引用一次,计数就加1,引用被释放了,计数就减一,当这个计数为0的时候,这个对象就能够被回收了。固然,这也就引起了一个问题:循环引用的对象是没法被识别出来而且被回收的。因此就有了第二种方法:
2.采用根搜索算法:
从一个根出发,搜索全部的可达对象,这样剩下的那些对象就是须要被回收的

19)、静态代理和动态代理的区别,什么场景使用?
由程序员建立或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态建立而成。
场景:著名的Spring框架、Hibernate框架等等都是动态代理的使用例子

20)、Java的异常体系
Throwable,Error,Exception

21)、谈谈你对解析与分派的认识。
解析:Java中方法调用的目标方法在Class文件里面都是常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用。这种解析的前提是:方法在程序真正运行以前就有一个能够肯定的调用版本,而且这个方法的调用版本在运行期是不可改变的,即“编译期可知,运行期不可变”,这类目标的方法的调用称为解析(Resolve)。

只要能被invokestatic和invokespecial指令调用的方法,均可以在解析阶段中肯定惟一的调用版本,符合条件的有静态方法(invokestatic指令)、私有方法、实例构造方法、父类方法(这3个是invokespecial指令),它们在类加载的的解析阶段就会将符号引用解析为该方法的直接引用。
分派:分派是多态性的体现,Java虚拟机底层提供了咱们开发中“重载”(Overload)“和重写”(Override)的底层实现。其中重载属于静态分派,而重写则是动态分派的过程。
解析调用必定是个静态的过程,在编译期就彻底肯定,在类加载的解析阶段就将涉及的符号引用所有转变为能够肯定的直接引用,不会延迟到运行期再去完成。

22)、Java中实现多态的机制是什么?
答:方法的重写Overriding和重载Overloading是Java多态性的不一样表现
重写Overriding是父类与子类之间多态性的一种表现
重载Overloading是一个类中多态性的一种表现.

23)、说说你对Java反射的理解
JAVA反射机制是在运行状态中, 对于任意一个类, 都可以知道这个类的全部属性和方法; 对于任意一个对象, 都可以调用它的任意一个方法和属性。 从对象出发,经过反射(Class类)能够取得取得类的完整信息(类名 Class类型,所在包、具备的全部方法 Method[]类型、某个方法的完整信息(包括修饰符、返回值类型、异常、参数类型)、全部属性 Field[]、某个属性的完整信息、构造器 Constructors),调用类的属性或方法本身的总结: 在运行过程当中得到类、对象、方法的全部信息。

24)、说说你对Java注解的理解
元注解
元注解的做用就是负责注解其余注解。java5.0的时候,定义了4个标准的meta-annotation类型,它们用来提供对其余注解的类型做说明。
1.@Target
2.@Retention
3.@Documented
4.@Inherited

25)、Java中String的了解
在源码中string是用final 进行修饰,它是不可更改,不可继承的常量。

26)、String为何要设计成不可变的?
一、字符串池的需求
字符串池是方法区(Method Area)中的一块特殊的存储区域。当一个字符串已经被建立而且该字符串在 池 中,该字符串的引用会当即返回给变量,而不是从新建立一个字符串再将引用返回给变量。若是字符串不是不可变的,那么改变一个引用(如: string2)的字符串将会致使另外一个引用(如: string1)出现脏数据。
二、容许字符串缓存哈希码
在java中经常会用到字符串的哈希码,例如: HashMap 。String的不变性保证哈希码始终一,所以,他能够不用担忧变化的出现。 这种方法意味着没必要每次使用时都从新计算一次哈希码——这样,效率会高不少。
三、安全
String普遍的用于java 类中的参数,如:网络链接(Network connetion),打开文件(opening files )等等。若是String不是不可变的,网络链接、文件将会被改变——这将会致使一系列的安全威胁。操做的方法本觉得链接上了一台机器,但实际上却不是。因为反射中的参数都是字符串,一样,也会引发一系列的安全问题。

27)、Object类的equal和hashCode方法重写,为何?
首先equals与hashcode间的关系是这样的:
一、若是两个对象相同(即用equals比较返回true),那么它们的hashCode值必定要相同;
二、若是两个对象的hashCode相同,它们并不必定相同(即用equals比较返回false)
因为为了提升程序的效率才实现了hashcode方法,先进行hashcode的比较,若是不一样,那没就没必要在进行equals的比较了,这样就大大减小了equals比较的次数,这对比须要比较的数量很大的效率提升是很明显的

28)、java的集合以及集合之间的继承关系

List,Set,Map的区别
Set是最简单的一种集合。集合中的对象不按特定的方式排序,而且没有重复对象。 Set接口主要实现了两个实现类:HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快
TreeSet :TreeSet类实现了SortedSet接口,可以对集合中的对象进行排序。
List的特征是其元素以线性方式存储,集合中能够存放重复对象。
ArrayList() : 表明长度能够改变得数组。能够对元素进行随机的访问,向ArrayList()中插入与删除元素的速度慢。
LinkedList(): 在实现中采用链表数据结构。插入和删除速度快,访问速度慢。
Map 是一种把键对象和值对象映射的集合,它的每个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
HashMap:Map基于散列表的实现。插入和查询“键值对”的开销是固定的。能够经过构造器设置容量capacity和负载因子load factor,以调整容器的性能。
LinkedHashMap: 相似于HashMap,可是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,由于它使用链表维护内部次序。
TreeMap : 基于红黑树数据结构的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparabel或Comparator决定)。TreeMap的特色在 于,你获得的结果是通过排序的。TreeMap是惟一的带有subMap()方法的Map,它能够返回一个子树。
WeakHashMao :弱键(weak key)Map,Map中使用的对象也被容许释放: 这是为解决特殊问题设计的。若是没有map以外的引用指向某个“键”,则此“键”能够被垃圾收集器回收。

List和Set和Map的实现方式以及存储方式
List:
经常使用实现方式有:ArrayList和LinkedList
ArrayList 的存储方式:数组,查询快
LinkedList的存储方式:链表,插入,删除快

Set:
经常使用实现方式有:HashSet和TreeSet
HashSet的存储方式:哈希码算法,加入的对象须要实现hashcode()方法,快速查找元素
TreeSet的存储方式:按序存放,想要有序就要实现Comparable接口

附加:
集合框架提供了2个实用类:collections(排序,复制、查找)和Arrays对数组进行(排序,复制、查找)

Map:
经常使用实现方式有:HashMap和TreeMap
HashMap的存储方式:哈希码算法,快速查找键值
TreeMap存储方式:对键按序存放

29)、数组(如arryList)中数组容量不够了,怎么扩容?
在JDK1.7中若是经过无参构造的话,初始数组容量是0,当数组进行add()添加时,才真正的分配容量,经过位运算,每次按照1.5倍的比例扩容。
在JDK1.6中,初始数组容量为10,每次经过cope of方式扩容1.5倍+1.

HashMap的实现原理,如何put数据和get数据?
在JDK1.6,JDK1.7中,HashMap采用数组+链表实现,即便用链表处理冲突,同一hash值的链表都存储在一个链表里。可是当位于一个链表中的元素较多,即hash值相等的元素较多时,经过key值依次查找的效率较低。而JDK1.8中,HashMap采用位数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减小了查找时间。
当链表数组的容量超过初始容量*加载因子(默认0.75)时,再散列将链表数组扩大2倍,把原链表数组的搬移到新的数组中。为何须要使用加载因子?为何须要扩容呢?由于若是填充比很大,说明利用的空间不少,若是一直不进行扩容的话,链表就会愈来愈长,这样查找的效率很低,扩容以后,将原来链表数组的每个链表分红奇偶两个子链表分别挂在新链表数组的散列位置,这样就减小了每一个链表的长度,增长查找效率。

HashMap在put时候,底层源码能够看出,当程序试图将一个key-value对象放入到HashMap中,首先根据该key的hashCode()返回值决定该Entry的存储位置,若是两个Entry的key的hashCode()方法返回值相同,那他们的存储位置相同,若是这两个Entry的key经过equals比较返回true,新添加的Entry的value将会覆盖原来的Entry的value,可是key不会被覆盖,反之,若是返回false,新添加的Entry将与集合中原有的Entry造成Entry链,新添加的位于头部,旧的位于尾部。
存:

取:

30)、ArrayMap和HashMap的对比
一、存储方式不一样
HashMap内部有一个HashMapEntry[]对象,每个键值对都存储在这个对象里,当使用put方法添加键值对时,就会new一个HashMapEntry对象,
二、添加数据时扩容时的处理不同,进行了new操做,从新建立对象,开销很大。ArrayMap用的是copy数据,因此效率相对要高。
三、ArrayMap提供了数组收缩的功能,在clear或remove后,会从新收缩数组,是否空间
四、ArrayMap采用二分法查找;
31)、List,Set,Map的区别
Set是最简单的一种集合。集合中的对象不按特定的方式排序,而且没有重复对象。 Set接口主要实现了两个实现类:HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快
TreeSet :TreeSet类实现了SortedSet接口,可以对集合中的对象进行排序。

List的特征是其元素以线性方式存储,集合中能够存放重复对象。
ArrayList() : 表明长度能够改变得数组。能够对元素进行随机的访问,向ArrayList()中插入与删除元素的速度慢。
LinkedList(): 在实现中采用链表数据结构。插入和删除速度快,访问速度慢。

Map 是一种把键对象和值对象映射的集合,它的每个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
HashMap:Map基于散列表的实现。插入和查询“键值对”的开销是固定的。能够经过构造器设置容量capacity和负载因子load factor,以调整容器的性能。
LinkedHashMap: 相似于HashMap,可是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,由于它使用链表维护内部次序。
TreeMap : 基于红黑树数据结构的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparabel或Comparator决定)。TreeMap的特色在 于,你获得的结果是通过排序的。TreeMap是惟一的带有subMap()方法的Map,它能够返回一个子树。
WeakHashMap :弱键(weak key)Map,Map中使用的对象也被容许释放: 这是为解决特殊问题设计的。若是没有map以外的引用指向某个“键”,则此“键”能够被垃圾收集器回收。

32)、HashMap和HashTable的区别
HashMap容许key和value为null;
HashMap是非同步的,线程不安全,也能够经过Collections.synchronizedMap()方法来获得一个同步的HashMap
HashMap存取速度更快,效率高
HashMap去掉了HashTable中的contains方法,加上了containsValue和containsKey方法

33)、HashMap与HashSet的区别

HashSet与HashMap怎么判断集合元素重复?
HashSet不能添加剧复的元素,当调用add(Object)方法时候,
首先会调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素;若是已存在则调用Object对象的equals方法判断是否返回true,若是为true则说明元素已经存在,如为false则插入元素。

集合Set实现Hash怎么防止碰撞
重写hashcode()和equles()方法

ArrayList和LinkedList的区别,以及应用场景
ArrayList是基于数组实现的,ArrayList线程不安全。
LinkedList是基于双链表实现的:
使用场景:
(1)若是应用程序对各个索引位置的元素进行大量的存取或删除操做,ArrayList对象要远优于LinkedList对象;
( 2 ) 若是应用程序主要是对列表进行循环,而且循环时候进行插入或者删除操做,LinkedList对象要远优于ArrayList对象;

34)、数组和链表的区别
数组:是将元素在内存中连续存储的;它的优势:由于数据是连续存储的,内存地址连续,因此在查找数据的时候效率比较高;它的缺点:在存储以前,咱们须要申请一块连续的内存空间,而且在编译的时候就必须肯定好它的空间的大小。在运行的时候空间的大小是没法随着你的须要进行增长和减小而改变的,当数据两比较大的时候,有可能会出现越界的状况,数据比较小的时候,又有可能会浪费掉内存空间。在改变数据个数时,增长、插入、删除数据效率比较低。
链表:是动态申请内存空间,不须要像数组须要提早申请好内存的大小,链表只需在用的时候申请就能够,根据须要来动态申请或者删除内存空间,对于数据增长和删除以及插入比数组灵活。还有就是链表中数据在内存中能够在任意的位置,经过应用来关联数据(就是经过存在元素的指针来联系)

35)、堆和树的区别
节点的顺序
在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。可是在堆中并不是如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。

内存占用
普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额外内存。堆仅仅使用一个数据来存储数组,且不使用指针。

平衡
二叉搜索树必须是“平衡”的状况下,其大部分操做的复杂度才能达到O(log n)。你能够按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树,可是在堆中实际上不须要整棵树都是有序的。咱们只须要知足对属性便可,因此在堆中平衡不是问题。由于堆中数据的组织方式能够保证O(log n) 的性能。

搜索
在二叉树中搜索会很快,可是在堆中搜索会很慢。在堆中搜索不是第一优先级,由于使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操做。

36)、什么是深拷贝和浅拷贝
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
深拷贝:对基本数据类型进行值传递,对引用数据类型,建立一个新的对象,并复制其内容,此为深拷贝。

37)、判断单链表成环与否?
使用快慢指针遍历链表:
慢指针:
从头节点开始,一次跳一个节点。
快指针:
从头节点开始,一次跳两个节点。
若是是成环的,这两个指针必定会相遇。

38)、开启线程的三种方式?
java有三种建立线程的方式,分别是继承Thread类、实现Runable接口和使用线程池

39)、线程和进程的区别?
线程是进程的子集,一个进程能够有不少线程,每条线程并行执行不一样的任务。不一样的进程使用不一样的内存空间,而全部的线程共享一片相同的内存空间。别把它和栈内存搞混,每一个线程都拥有单独的栈内存用来存储本地数据。

40)、为何要有线程,而不是仅仅用进程?
线程能够增长并发的程度啊。其实多进程也是能够并发,可是为何要是线程呢?由于线程是属于进程的,是个轻量级的对象。因此再切换线程时只须要作少许的工做,而切换进程消耗很大。这是从操做系统角度讲。
从用户程序角度讲,有些程序在逻辑上须要线程,好比扫雷,它须要一个线程等待用户的输入,另外一个线程的来更新时间。还有一个例子就是聊天程序,一个线程是响应用户输入,一个线程是响应对方输入。若是没有多线程,那么只能你说一句我说一句,你不说我这里就不能动,我还不能连续说。因此用户程序有这种须要,操做系统就要提供响应的机制

41)、run()和start()方法区别
这个问题常常被问到,但仍是能今后区分出面试者对Java线程模型的理解程度。start()方法被用来启动新建立的线程,并且start()内部调用了run()方法,这和直接调用run()方法的效果不同。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。

42)、如何控制某个方法容许并发访问线程的个数?
semaphore.acquire() 请求一个信号量,这时候的信号量个数-1(一旦没有可以使用的信号量,也即信号量个数变为负数时,再次请求的时候就会阻塞,直到其余线程释放了信号量)
semaphore.release() 释放一个信号量,此时信号量个数+1

43)、在Java中wait和seelp方法的不一样
Java程序中wait 和 sleep都会形成某种形式的暂停,它们能够知足不一样的须要。wait()方法用于线程间通讯,若是等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程中止执行一段时间,但不会释放锁。

44)、谈谈wait/notify关键字的理解
等待对象的同步锁,须要得到该对象的同步锁才能够调用这个方法,不然编译能够经过,但运行时会收到一个异常:IllegalMonitorStateException。
调用任意对象的 wait() 方法致使该线程阻塞,该线程不可继续执行,而且该对象上的锁被释放。
唤醒在等待该对象同步锁的线程(只唤醒一个,若是有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM肯定唤醒哪一个线程,并且不是按优先级。
调用任意对象的notify()方法则致使因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到得到锁后才真正可执行)。

45)、什么致使线程阻塞?
阻塞式方法是指程序会一直等待该方法完成期间不作其余事情,ServerSocket的accept()方法就是一直等待客户端链接。这里的阻塞是指调用结果返回以前,当前线程会被挂起,直到获得结果以后才会返回。此外,还有异步和非阻塞式方法在任务完成前就返回。

46)、线程如何关闭?
一种是调用它里面的stop()方法
另外一种就是你本身设置一个中止线程的标记 (推荐这种)

47)、讲一下java中的同步的方法(另外一种问法:数据一致性如何保证?)
1.即有synchronized关键字修饰的方法。
2.同步代码块(如:双重判断的单例模式)
3.使用特殊域变量(volatile)实现线程同步
4.使用重入锁实现线程同步
5.使用局部变量实现线程同步

48)、如何保证线程安全?
1.synchronized;
2.Object方法中的wait,notify;
3.ThreadLocal机制 来实现的。

49)、如何实现线程同步?
一、synchronized关键字修改的方法。二、synchronized关键字修饰的语句块三、使用特殊域变量(volatile)实现线程同步

50)、两个进程同时要求写或者读,能不能实现?如何防止进程的同步?
能够实现的。
同步方式有: 互斥锁、条件变量、读写锁、记录锁(文件锁)和信号灯

51)、线程间操做List
List list = Collections.synchronizedList(new ArrayList());

52)、Synchronized用法及原理
用法:修饰静态方法、实例方法、代码块
原理:不是一两句话能说清,建议去深刻了解一下。

53)、谈谈对Synchronized关键字,类锁,方法锁,重入锁的理解
java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,可是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。咱们知道,类的对象实例能够有不少个,可是每一个类只有一个class对象,因此不一样对象实例的对象锁是互不干扰的,可是每一个类只有一个类锁。可是有一点必须注意的是,其实类锁只是一个概念上的东西,并非真实存在的,它只是用来帮助咱们理解锁定实例方法和静态方法的区别的

54)、static synchronized 方法的多线程访问和做用
1.synchronized static是某个类的范围,synchronized static cSync{}防止多个线程同时访问这个类中的synchronized static 方法。它能够对类的全部对象实例起做用。

2.synchronized 是某实例的范围,synchronized isSync(){}防止多个线程同时访问这个实例中的synchronized 方法。

55)、同一个类里面两个synchronized方法,两个线程同时访问的问题
同一个object中多个方法都加了synchronized关键字的时候,其中调用任意方法以后需等该方法执行完成才能调用其余方法,即同步的,阻塞的;
此结论一样适用于对于object中使用synchronized(this)同步代码块的场景;
synchronized锁定的都是当前对象!

56)、volatile的做用,原理,性能。
做用:一、保持内存可见性 二、防止指令重排
原理:获取JIT(即时Java编译器,把字节码解释为机器语言发送给处理器)的汇编代码,发现volatile多加了lock addl指令,这个操做至关于一个内存屏障,使得lock指令后的指令不能重排序到内存屏障前的位置。这也是为何JDK1.5之后能够使用双锁检测实现单例模式。
lock前缀的另外一层意义是使得本线程工做内存中的volatile变量值当即写入到主内存中,而且使得其余线程共享的该volatile变量无效化,这样其余线程必须从新从主内存中读取变量值。
性能:读操做与普通变量无差异,写操做会慢一些,大多状况比锁消耗低。

57)、synchronized 和volatile 关键字的区别

1.volatile本质是在告诉jvm当前变量在寄存器(工做内存)中的值是不肯定的,须要从主存中读取;synchronized则是锁定当前变量,只有当前线程能够访问该变量,其余线程被阻塞住。
2.volatile仅能使用在变量级别;synchronized则能够使用在变量、方法、和类级别的
3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则能够保证变量的修改可见性和原子性
4.volatile不会形成线程的阻塞;synchronized可能会形成线程的阻塞。
5.volatile标记的变量不会被编译器优化;synchronized标记的变量能够被编译器优化

58)、synchronized与Lock的区别及使用场景
synchronized原始采用的是CPU悲观锁机制,即线程得到的是独占锁。独占锁意味着其余线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引发线程上下文切换,当有不少线程竞争锁的时候,会引发CPU频繁的上下文切换致使效率很低;
而Lock用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操做,若是由于冲突失败就重试,直到成功为止。乐观锁实现的机制就是CAS操做(Compare and Swap)。咱们能够进一步研究ReentrantLock的源代码,会发现其中比较重要的得到锁的一个方法是compareAndSetState。这里其实就是调用的CPU提供的特殊指令。
使用场景:在性能上来讲,若是竞争资源不激烈,二者的性能是差很少的,而当竞争资源很是激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。因此说,在具体使用时要根据适当状况选择。

59)、ReentrantLock 、synchronized和volatile比较
java在过去很长一段时间只能经过synchronized关键字来实现互斥,它有一些缺点。好比你不能扩展锁以外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 经过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义且它还具备可扩展性。

60)、死锁的四个必要条件?怎么避免死锁?
死锁产生的缘由

  1. 系统资源的竞争
    系统资源的竞争致使系统资源不足,以及资源分配不当,致使死锁。
  2. 进程运行推动顺序不合适
    互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时如有其余进程请求该资源,则请求进程只能等待。
    请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其余进程占有,此时请求进程被阻塞,但对本身已得到的资源保持不放。
    不可剥夺条件:进程所得到的资源在未使用完毕以前,不能被其余进程强行夺走,即只能 由得到该资源的进程本身来释放(只能是主动释放)。
    循环等待条件: 若干进程间造成首尾相接循环等待资源的关系
    这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不知足,就不会发生死锁。
    死锁的避免与预防:
    死锁避免的基本思想:
    系统对进程发出每个系统可以知足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若是分配后系统可能发生死锁,则不予分配,不然予以分配。这是一种保证系统不进入死锁状态的动态策略。
    理解了死锁的缘由,尤为是产生死锁的四个必要条件,就能够最大可能地避免、预防和解除死锁。因此,在系统设计、进程调度等方面注意如何让这四个必要条件不成立,如何肯定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的状况下占用资源。所以,对资源的分配要给予合理的规划。
    死锁避免和死锁预防的区别:
    死锁预防是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而死锁避免则不那么严格的限制产生死锁的必要条件的存在,由于即便死锁的必要条件存在,也不必定发生死锁。死锁避免是在系统运行过程当中注意避免死锁的最终发生。

61)、什么是线程池,如何使用?
建立线程要花费昂贵的资源和时间,若是任务来了才建立线程那么响应时间会变长,并且一个进程能建立的线程数有限。为了不这些问题,在程序启动的时候就建立若干线程来响应处理,它们被称为线程池,里面的线程叫工做线程。从JDK1.5开始,Java API提供了Executor框架让你能够建立不一样的线程池。好比单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合不少生存期短的任务的程序的可扩展线程池)

62)、谈谈对多线程的理解
线程是由一个主线程和不少个子线程组成的,主线程消失,子线程也会消失,可是子线程消失其中一个主线程不会消失
线程的生命周期分为5个步骤像人的一辈子同样,这5个步骤分别对应了5个方法
新生-->启动-->运行-->阻塞-->销毁
继承Thread类or实现runnable方法-->start-->run-->sleep(睡眠)or wait(挂起)-->destroy

63)、多线程有什么要注意的问题?
给线程起有意义的名字,这样方便找Bug
缩小同步范围,从而减小锁的争用,例如对于 synchronized,应该尽可能使用同步块而不是同步方法
多用同步工具少用 wait() 和 notify()。首先,CountDownLatch, CyclicBarrier, Semaphore 和Exchanger 这些同步类简化了编码操做,而用 wait() 和 notify() 很难实现复杂控制流;其次,这些同步类是由最好的企业编写和维护,在后续的 JDK 中还会不断优化和完善。
64)、使用BlockingQueue实现生产者消费者问题
多用并发集合少用同步集合,例如应该使用 ConcurrentHashMap 而不是 Hashtable
使用本地变量和不可变类来保证线程安全
使用线程池而不是直接建立线程,这是由于建立线程代价很高,线程池能够有效地利用有限的线程来启动任务

本身去设计网络请求框架,怎么作?
这种并无一个彻底正确的答案,看我的的思路与理解

65)、okhttp源码
本身看一遍源码便可,最好可以手写出他的流程。

从网络加载一个10M的图片,说下注意事项
图片缓存、异常恢复、质量压缩,从这几方面说就行了

66)、TCP的3次握手和四次挥手
三次握手:
第一次:客户端发送请求到服务器,服务器知道客户端发送,本身接收正常。SYN=1,seq=x
第二次:服务器发给客户端,客户端知道本身发送、接收正常,服务器接收、发送正常。ACK=1,ack=x+1,SYN=1,seq=y
第三次:客户端发给服务器:服务器知道客户端发送,接收正常,本身接收,发送也正常.seq=x+1,ACK=1,ack=y+1

四次挥手:
第一次:客户端请求断开FIN,seq=u
第二次:服务器确认客户端的断开请求ACK,ack=u+1,seq=v
第三次:服务器请求断开FIN,seq=w,ACK,ack=u+1
第四次:客户端确认服务器的断开ACK,ack=w+1,seq=u+1

为何链接的时候是三次握手,关闭的时候倒是四次握手?
由于当Server端收到Client端的SYN链接请求报文后,能够直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。可是关闭链接时,当Server端收到FIN报文时,极可能并不会当即关闭SOCKET,因此只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端全部的报文都发送完了,我才能发送FIN报文,所以不能一块儿发送。故须要四步握手。

为何不能用两次握手进行链接?
3次握手完成两个重要的功能,既要双方作好发送数据的准备工做(双方都知道彼此已准备好),也要容许双方就初始序列号进行协商,这个序列号在握手过程当中被发送和确认。
如今把三次握手改为仅须要两次握手,死锁是可能发生的。

为何TIME_WAIT状态须要通过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
虽然按道理,四个报文都发送完毕,咱们能够直接进入CLOSE状态了,可是咱们必须假象网络是不可靠的,有能够最后一个ACK丢失。因此TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server若是没有收到ACK,将不断重复发送FIN片断。因此Client不能当即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK以后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。若是在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片断在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。若是直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP链接。

TCP与UDP的区别
tcp是面向链接的,因为tcp链接须要三次握手,因此可以最低限度的下降风险,保证链接的可靠性。
udp 不是面向链接的,udp创建链接前不须要与对象创建链接,不管是发送仍是接收,都没有发送确认信号。因此说udp是不可靠的。
因为udp不须要进行确认链接,使得UDP的开销更小,传输速率更高,因此实时行更好。

67)、TCP与UDP的应用
从特色上咱们已经知道,TCP 是可靠的但传输速度慢 ,UDP 是不可靠的但传输速度快。所以在选用具体协议通讯时,应该根据通讯数据的要求而决定。 
若通讯数据完整性需让位与通讯实时性,则应该选用 TCP 协议(如文件传输、重要状态的更新等);反之,则使用 UDP 协议(如视频传输、实时通讯等)。

68)、Http https区别,此处延伸:https的实现原理
一、https协议须要到ca申请证书,通常免费证书较少,于是须要必定费用。
二、http是超文本传输协议,信息是明文传输,https则是具备安全性的ssl加密传输协议。
三、http和https使用的是彻底不一样的链接方式,用的端口也不同,前者是80,后者是443。
四、http的链接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
五、https实现原理:
(1)客户使用https的URL访问Web服务器,要求与Web服务器创建SSL链接。
(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
(3)客户端的浏览器与Web服务器开始协商SSL链接的安全等级,也就是信息加密的等级。
(4)客户端的浏览器根据双方赞成的安全等级,创建会话密钥,而后利用网站的公钥将会话密钥加密,并传送给网站。
(5)Web服务器利用本身的私钥解密出会话密钥。
(6)Web服务器利用会话密钥加密与客户端之间的通讯。
七、Http位于TCP/IP模型中的第几层?为何说Http是可靠的数据传输协议?
tcp/ip的五层模型:
从下到上:物理层->数据链路层->网络层->传输层->应用层
其中tcp/ip位于模型中的网络层,处于同一层的还有ICMP(网络控制信息协议)。http位于模型中的应用层
因为tcp/ip是面向链接的可靠协议,而http是在传输层基于tcp/ip协议的,因此说http是可靠的数据传输协议。

八、HTTP连接的特色
HTTP链接最显著的特色是客户端发送的每次请求都须要服务器回送响应,在请求结束后,会主动释放链接。
从创建链接到关闭链接的过程称为“一次链接”。

HTTP报文结构
一个HTTP请求报文由四个部分组成:请求行、请求头部、空行、请求数据。
1.请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。好比 GET /data/info.html HTTP/1.1
2.请求头部
HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(通常是GET或者 POST)。若有必要,客户程序还能够选择发送其余的请求头。大多数请求头并非必需的,但Content-Length除外。对于POST请求来讲 Content-Length必须出现。
3.空行
它的做用是经过一个空行,告诉服务器请求头部到此为止。
4.请求数据
若方法字段是GET,则此项为空,没有数据。若方法字段是POST,则一般来讲此处放置的就是要提交的数据

HTTP与HTTPS的区别以及如何实现安全性
区别:http是明文传输,传输的数据极可能被中间节点获取,从而致使数据传输不安全 
https是加密传输,能够保证数据的传输安全
如何实现:http是应用层协议,它会将要传输的数据以明文的方式给传输层,这样显然不安全。https则是在应用层与传输层之间又加了一层,该层遵照SSL/TLS协议,用于数据加密。

如何验证证书的合法性?
一、证书是不是信任的有效证书。所谓信任:浏览器内置了信任的根证书,就是看看web服务器的证书是否是这些信任根发的或者信任根的二级证书机构颁发的。所谓有效,就是看看web服务器证书是否在有效期,是否被吊销了。二、对方是否是上述证书的合法持有者。简单来讲证实对方是否持有证书的对应私钥。验证方法两种,一种是对方签个名,我用证书验证签名;另一种是用证书作个信封,看对方是否能解开。以上的全部验证,除了验证证书是否吊销须要和CA关联,其余均可以本身完成。验证正式是否吊销能够采用黑名单方式或者OCSP方式。黑名单就是按期从CA下载一个名单列表,里面有吊销的证书序列号,本身在本地比对一下就行。优势是效率高。缺点是不实时。OCSP是实时链接CA去验证,优势是实时,缺点是效率不高。

client如何肯定本身发送的消息被server收到?
HTTP协议里,有请求就有响应,根据响应的状态吗就能知道。

HttpClient与HttpUrlConnection的区别 (此处延伸:Volley里用的哪一种请求方式(2.3前HttpClient,2.3后HttpUrlConnection)
首先HttpClient和HttpUrlConnection 这两种方式都支持Https协议,都是以流的形式进行上传或者下载数据,也能够说是以流的形式进行数据的传输,还有ipv6,以及链接池等功能。HttpClient这个拥有很是多的API,因此若是想要进行扩展的话,而且不破坏它的兼容性的话,很难进行扩展,也就是这个缘由,Google在Android6.0的时候,直接就弃用了这个HttpClient.
而HttpUrlConnection相对来讲就是比较轻量级了,API比较少,容易扩展,而且可以知足Android大部分的数据传输。比较经典的一个框架volley,在2.3版本之前都是使用HttpClient,在2.3之后就使用了HttpUrlConnection。

69)、WebSocket与socket的区别
1.WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通讯(full-duplex)。一开始的握手须要借助HTTP请求完成。
2.Socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把...
3.区别 Socket是传输控制层协议,WebSocket是应用层协议。

70)、谈谈你对安卓签名的理解。
每一个应用都必须签名
应用能够被不一样的签名文件签名(若是有源代码或者反编译后从新编译)
同一个应用若是签名不一样则不能覆盖安装

71)、请解释安卓为啥要加签名机制?
发送者的身份认证:因为开发商可能经过使用相同的 Package Name 来混淆替换已经安装的程序,以此保证签名不一样的包不被替换
保证信息传输的完整性:签名对于包中的每一个文件进行处理,以此确保包中内容不被替换
防止交易中的抵赖发生:Market(应用市场)对软件的要求

72)、视频加密传输
DES加密。用java中提供的加密包。
将视频文件的数据流前100个字节中的每一个字节与其下标进行异或运算。解密时只需将加密过的文件再进行一次异或运算便可。

73)、App 是如何沙箱化,为何要这么作?
在Android系统中,应用(一般)都在一个独立的沙箱中运行,即每个Android应用程序都在它本身的进程中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik通过优化,容许在有限的内存中同时高效地运行多个虚拟机的实例,而且每个Dalvik应用做为一个独立的Linux进程执行。Android这种基于Linux的进程“沙箱”机制,是整个安全设计的基础之一。
Android扩展了Linux内核安全模型的用户与权限机制,将多用户操做系统的用户隔离机制巧妙地移植为应用程序隔离。将UID(一个用户标识)不一样的应用程序天然造成资源隔离,如此便造成了一个操做系统级别的应用程序“沙箱”。

2、Android面试题(基础+进阶)(必须)

1)、四大组件是什么(这个不知道的话,不必去面试了,转行吧)
Android四大组件有Activity,Service服务,Content Provider内容提供,BroadcastReceiver。

2)、四大组件的生命周期和简单用法
activity:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()
3)、Service:
service 启动方式有两种,一种是经过startService()方式进行启动,另外一种是经过bindService()方式进行启动。不一样的启动方式他们的生命周期是不同.
经过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,须要注意一下几个问题,第一:当咱们经过startService被调用之后,屡次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被屡次调用当咱们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当咱们经过startService启动时候,经过intent传值,在onStartConmon()方法中获取值的时候,必定要先判断intent是否为null。
经过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 这种方式进行启动service好处是更加便利activity中操做service,好比加入service中有几个方法,a,b ,若是要在activity中调用,在须要在activity获取ServiceConnection对象,经过ServiceConnection来获取service中内部类的类对象,而后经过这个类对象就能够调用类中的方法,固然这个类须要继承Binder对象
contentProvider:contentProvider的生命周期、理解应该跟进程同样,它做为系统应用组件、其生命周期应该跟app应用的生命周期相似,只是它属于系统应用、因此随系统启动而初始化,随系统关机而结束;但也存在其余状态下结束进程、好比说系统内存不够时,进行内存回收、会根据生成时间态、用户操做等状况进行是否内存回收。
BroadcastReceiver:广播的生命周期从调用开始到onReceiver执行完毕结束,须要注意的是,通常广播的生命周期都极短,须要在10s内处理完onReceiver中的全部工做,因此,通常不进行耗时长的工做,若是有耗时长的工做,应当经过Intent传递给Service进行处理。(注意,不要在onReceiver中开启线程进行耗时任务处理,不然,在10s后,该线程会变成空线程,从而致使任务的丢失。一样的,也不要使用bindService来绑定服务。)
值得注意的是,若是是在代码中动态注册的广播,如:在Activity注册,那么在Activity的onDestory中须要使用unregisterReceiver注销广播。

4)、Activity之间的通讯方式
Intent
借助类的静态变量
借助全局变量/Application
借助外部工具 
借助SharedPreference 
使用Android数据库SQLite 
赤裸裸的使用File 
Android剪切板
借助Service

5)、横竖屏切换的时候,Activity 各类状况下的生命周期
分两种状况:
1.不设置Activity的android:configChanges,或设置Activity的android:configChanges="orientation",或设置Activity的android:configChanges="orientation|keyboardHidden",切屏会从新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。
横竖屏切换形成 activity 的生命周期
onPause()-onSaveInstanceState()-onStop()-onDestroy()-onCreat()-onStart()-onRestoreInstanceState()-onResume()即会致使 activity 的销毁和重建 。

2.配置 android:configChanges="orientation|keyboardHidden|screenSize",才不会销毁 activity,且只调用 onConfigurationChanged方法。
onSaveInstanceState() 与onRestoreIntanceState() 资源相关的系统配置发生改变或者资源不足时(例如屏幕旋转),当前 Activity 会销毁,而且在 onStop 以前回调 onSaveInstanceState 保存数据,在从新建立 Activity 的时候在onStart 以后回调 onRestoreInstanceState。其中 Bundle 数据会传到 onCreate(不必定有数据)和 onRestoreInstanceState(必定有数据)。
用户或者程序员主动去销毁一个 Activity 的时候不会回调(如代码中 finish()或用户按下 back,不会回调),其余状况都会调用,来保存界面信息。

6)、Activity与Fragment之间生命周期比较
a. 在建立的过程当中,是 Activity 带领 Fragment 执行生命周期的方法,因此它们生命周期执行的顺序以下:

Activity -- onCreate() ,
Fragment -- onAttach() -> onCreate() -> onCreateView() -> onActivityCreated

.

Activity -- onStart()

Fragment -- onStart()


Activity -- onResume()

Fragment -- onResume()


最后,在销毁时是 Fragment 带领 Activity 执行生命周期的方法:

Fragment -- onPause()

Activity -- onPause()


Fragment -- onStop()

Activity -- onStop()


Fragment -- onDestroyView() -> onDestroy() -> onDetach()

Activity -- onDestroy()

Activity上有Dialog的时候按Home键时的生命周期
有 Dialog 和 无 Dialog 按 Home 键效果同样:

  1. 正常启动: onCreate() -> onStart() -> onResume()
  2. 按 home 键: onPause() -> onStop()
  3. 再次启动: onRestart() -> onStart() -> onResume()

7)、两个Activity 之间跳转时必然会执行的是哪几个方法?
a. 正常状况下 Activity A 跳转到 Activity B 时:
A调用 onCreate() 方法 -> onStart() 方法 -> onResume() 方法,此时 A 前台可见。当 A 跳转到 B 时,A 调用 onPause() 方法,而后调用新的 Activity B 中的 onCreate() 方法 -> onStart() 方法 -> onResume() 方法。最后 A 再调用onStop()方法。
b. 当 Activity B 为透明主题时:
除了最后 Activity A 不调用 onStop() 方法以外,其它都和 a 中的同样。

8)、Activity的四种启动模式对比
此处延伸:栈(First In Last Out)与队列(First In First Out)的区别
区别:队列先进先出,栈先进后出
对插入和删除操做的"限定"。 栈是限定只能在表的一端进行插入和删除操做的线性表。 队列是限定只能在表的一端进行插入和在另外一端进行删除操做的线性表。
遍历数据速度不一样

9)、standard 模式
这是默认模式,每次激活Activity时都会建立Activity实例,并放入任务栈中。使用场景:大多数Activity。
singleTop 模式
若是在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),不然就会建立新的实例并放入栈顶,即便栈中已经存在该Activity的实例,只要不在栈顶,都会建立新的实例。使用场景如新闻类或者阅读类App的内容页面。
singleTask 模式
若是在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,所以在它上面的实例将会被移出栈。若是栈中不存在该实例,将会建立新的实例放入栈中。使用场景如浏览器的主界面。无论从多少个应用启动浏览器,只会启动主界面一次,其他状况都会走onNewIntent,而且会清空主界面上面的其余页面。
singleInstance 模式
在一个新栈中建立该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果至关于多个应用共享一个应用,无论谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,若是用于中间页面,跳转会有问题,好比:A -> B (singleInstance) -> C,彻底退出后,在此启动,首先打开的是B。

10)、Activity状态保存于恢复
当 Activity 在异常状况( 系统内存不足或者系统配置发生了改变等 )被销毁重建后, 在销毁的时候 Activity 会调用 onSaveInstanceState() 方法用于保存 Activity 相关的状态和数据,而后在重建后的 Activity 的中咱们能够经过 onCreate() 或者 onRestoreInstanceState() 方法恢复数据,这里咱们须要注意的是若是经过 onCreate() 方法恢复,那么得先判断它的 intent 参数 是否为空,若是在 onRestoreInstanceState() 方法恢复就不会,由于只要 onRestoreInstanceState() 方法被调用就说明必定有数据,不会为空。Google 推荐使用 onRestoreInstanceState() 方法。

11)、如何实现Fragment的滑动?
将Fragment与viewpager绑定,经过viewpager中的touch事件,会进行move事件的滑动处理。

12)、fragment之间传递数据的方式?
一、在fragment中设置一个方法,而后进行调用
二、采起接口回调的方式进行数据传递。
三、广播或者是使用三方开源框架:EventBus

13)、Activity 怎么和Service 绑定?怎么在Activity 中启动本身对应的Service?
一、activity能进行绑定得益于Serviece的接口。为了支持Service的绑定,实现onBind方法。
二、Service和Activity的链接能够用ServiceConnection来实现。须要实现一个新的ServiceConnection,重现onServiceConnected和OnServiceDisconnected方法,一旦链接创建,就能获得Service实例的引用。
三、执行绑定,调用bindService方法,传入一个选择了要绑定的Service的Intent(显示或隐式)和一个你实现了的ServiceConnection的实例

14)、service和activity怎么进行数据交互?
1.经过 broadcast:经过广播发送消息到 activitry
2.经过 Binder:经过与 activity 进行绑定
(1)添加一个继承 Binder 的内部类,并添加相应的逻辑方法。
(2)重写 Service 的 onBind 方法,返回咱们刚刚定义的那个内部类实例。
(3)Activity 中建立一个 ServiceConnection 的匿名内部类,而且 重 写 里 面 的 onServiceConnected 方 法 和onServiceDisconnected 方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用(在onServiceConnected方法中,咱们能够获得一个刚才那个 service 的 binder 对象,经过对这个 binder 对象进行向下转型,获得咱们那个自定义的 Binder 实例,有了这个实例,作能够调用这个实例里面的具体方法进行须要的操做了)。

15)、Service的开启方式,请描述一下Service 的生命周期,请描述一下Service 的生命周期
service 启动方式有两种,一种是经过startService()方式进行启动,另外一种是经过bindService()方式进行启动。不一样的启动方式他们的生命周期是不同.
经过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,须要注意一下几个问题,第一:当咱们经过startService被调用之后,屡次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被屡次调用当咱们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当咱们经过startService启动时候,经过intent传值,在onStartConmon()方法中获取值的时候,必定要先判断intent是否为null。
经过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 这种方式进行启动service好处是更加便利activity中操做service,好比加入service中有几个方法,a,b ,若是要在activity中调用,在须要在activity获取ServiceConnection对象,经过ServiceConnection来获取service中内部类的类对象,而后经过这个类对象就能够调用类中的方法,固然这个类须要继承Binder对象

16)、请描述一下广播BroadcastReceiver的理解
广播,是一个全局的监听器,属于Android四大组件之一。Android 广播分为两个角色:广播发送者、广播接收者。做用是监听 / 接收 应用 App 发出的广播消息,并 作出响应
可应用在:
Android不一样组件间的通讯(含 :应用内 / 不一样应用之间)
多线程通讯
与 Android 系统在特定状况下的通讯
如:电话呼入时、网络可用时

17)、Broadcast注册方式与区别 (此处延伸:什么状况下用动态注册)
Broadcast广播,注册方式主要有两种.
第一种是静态注册,也可成为常驻型广播,这种广播须要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即便退出了页面,也能够收到广播这种广播通常用于想开机自启动啊等等,因为这种注册的方式的广播是常驻型广播,因此会占用CPU的资源。
第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫很是驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,咱们一般运用在更新UI方面。这种注册方式优先级较高。最后须要解绑,否会会内存泄露
广播是分为有序广播和无序广播。

在manifest 和代码中如何注册和使用BroadcastReceiver?
          

18)、本地广播和全局广播有什么差异?
BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通讯的一种方式
LocalBroadcastReceiver仅在本身的应用内发送接收广播,也就是只有本身的应用能收到,数据更加安全广播只在这个程序里,并且效率更高。

19)、BroadcastReceiver,LocalBroadcastReceiver 区别
1、应用场景不一样
一、BroadcastReceiver用于应用之间的传递消息;
二、而LocalBroadcastManager用于应用内部传递消息,比broadcastReceiver更加高效。
2、使用安全性不一样
一、BroadcastReceiver使用的Content API,因此本质上它是跨应用的,因此在使用它时必需要考虑到不要被别的应用滥用;
二、LocalBroadcastManager不须要考虑安全问题,由于它只在应用内部有效。

20)、AlertDialog,popupWindow区别
(1)Popupwindow在显示以前必定要设置宽高,Dialog无此限制。
(2)Popupwindow默认不会响应物理键盘的back,除非显示设置了popup.setFocusable(true);而在点击back的时候,Dialog会消失。
(3)Popupwindow不会给页面其余的部分添加蒙层,而Dialog会。

(4)Popupwindow没有标题,Dialog默认有标题,能够经过dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消标题
(5)两者显示的时候都要设置Gravity。若是不设置,Dialog默认是Gravity.CENTER。
(6)两者都有默认的背景,均可以经过setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉。
最本质的区别:AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还能够作事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当咱们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。

21)、讲解一下Context 
Context是一个抽象基类。在翻译为上下文,也能够理解为环境,是提供一些程序的运行环境基础信息。Context下有两个子类,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity,因此Activity和Service以及Application的Context是不同的,只有Activity须要主题,Service不须要主题。Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各类承担着不一样的做用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的,所以在绝大多数场景下,Activity、Service和Application这三种类型的Context都是能够通用的。不过有几种场景比较特殊,好比启动Activity,还有弹出Dialog。出于安全缘由的考虑,Android是不容许Activity或Dialog凭空出现的,一个Activity的启动必需要创建在另外一个Activity的基础之上,也就是以此造成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),所以在这种场景下,咱们只能使用Activity类型的Context,不然将会出错。
getApplicationContext()和getApplication()方法获得的对象都是同一个application对象,只是对象的类型不同。
Context数量 = Activity数量 + Service数量 + 1 (1为Application)

22)、Android属性动画特性
(1) 对任意对象的属性执行动画操做:属性动画容许对任意对象的属性执行动画操做,由于属性动画的性质是经过反射实现的。
(2)可改变背景颜色。
(3)真正改变 View 自己:由于是经过反射改变其属性,并刷新,如改变width,他会搜索getWidth(),反射获取,再经过进行某种计算,将值经过setWidth()设置进去并更新。

23)、LinearLayout、RelativeLayout、FrameLayout的特性及对比,并介绍使用场景。
RelativeLayout的onMeasure过程
根据源码咱们发现RelativeLayout会根据2次排列的结果对子View各作一次measure。
首先RelativeLayout中子View的排列方式是基于彼此的依赖关系,在肯定每一个子View的位置的时候,须要先给全部的子View排序一下,因此须要横向纵向分别进行一次排序测量

LinearLayout的onMeasure过程
LinearLayout会先作一个简单横纵方向判断
须要注意的是在每次对child测量完毕后,都会调用child.getMeasuredHeight()/getMeasuredWidth()获取该子视图最终的高度,并将这个高度添加到mTotalLength中。
可是getMeasuredHeight暂时避开了lp.weight>0且高度为0子View,由于后面会将把剩余高度按weight分配给相应的子View。所以能够得出如下结论:
(1)若是咱们在LinearLayout中不使用weight属性,将只进行一次measure的过程。(若是使用weight属性,则遍历一次wiew测量后,再遍历一次view测量)
(2)若是使用了weight属性,LinearLayout在第一次测量时获取全部子View的高度,以后再将剩余高度根据weight加到weight>0的子View上。因而可知,weight属性对性能是有影响的。
1)RelativeLayout慢于LinearLayout是由于它会让子View调用2次measure过程,而LinearLayout只需一次,可是有weight属性存在时,LinearLayout也须要两次measure。
2)在不响应层级深度的状况下,使用Linearlayout而不是RelativeLayout。

24)、谈谈对接口与回调的理解
接口回调就是指: 能够把使用某一接口的类建立的对象的引用赋给该接口声明的接口变量,那么该接口变量就能够调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。

25)、Android中View,SurfaceView和GLSurfaceView
View:显示视图,内置画布,提供图形绘制函数,触屏事件,按键事件函数;必须在UI线程中更新画面,速度较慢。
SurfaceView:基于View视图进行拓展的视图类,更适合2D游戏的开发;是View的子类,相似双缓机制,在新的线程中更新画面,因此刷新界面速度比View快。(双缓机制:即前台缓存和后台缓存,后台缓存计算场景、产生画面,前台缓存显示后台缓存已画好的画面。)
GLSurfaceView:基于SurfaceView视图再次进行扩展的视图类,专用于3D游戏开发的视图;是SurfaceView的子类,OpenGL专用。(OpenGL:是一个开放的三维图形软件包。)

26)、序列化的做用,以及Android两种序列化的区别
做用:java序列化主要有2个做用:
对象持久化,对象生存在内存中,想把一个对象持久化到磁盘,必须已某种方式来组织这个对象包含的信息,这种方式就是序列化;
远程网络通讯,内存中的对象不能直接进行网络传输,发送端把对象序列化成网络可传输的字节流,接收端再把字节流还原成对象。

Serializable Java 序列化接口 在硬盘上读写 读写过程当中有大量临时变量的生成,内部执行大量的i/o操做,效率很低。
Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中

27)、差值器和估值器
差值器: 根据时间流逝的百分比计算当前属性改变的百分比。
估值器: 根据当前属性改变的百分比计算改变后的属性值

28)、Android中数据存储方式
1 使用SharedPreferences存储数据
适用范围:保存少许的数据,且这些数据的格式很是简单:字符串型、基本类型的值。
好比应用程序的各类配置信息(如是否打开音效等),解锁口 令密码等
核心原理:保存基于XML文件存储的key-value键值对数据,一般用来存储一些简单的配置信息。

2 文件存储数据
核心原理: Context提供了两个方法来打开数据文件里的文件IO流:
FileInputStream openFileInput(String name);
FileOutputStream openFileOutput(String name , int mode)
3 SQLite数据库存储数据
4 使用ContentProvider存储数据
5 网络存储数据
29)、Requestlayout,onlayout,onDraw,DrawChild区别与联系
requestLayout()方法 :会致使调用measure()过程 和 layout()过程 。 说明:只是对View树从新布局layout过程包括measure()和layout()过程,不会调用draw()过程,但不会从新绘制 任何视图包括该调用者自己。
onLayout()方法(若是该View是ViewGroup对象,须要实现该方法,对每一个子视图进行布局)
调用onDraw()方法绘制视图自己 (每一个View都须要重载该方法,ViewGroup不须要实现该方法)
drawChild()去从新回调每一个子视图的draw()方法

30)、invalidate和postInvalidate的区别及使用
一、postInvalidate() 方法在非 UI 线程中调用,通知 UI 线程重绘。
二、invalidate()方法在 UI 线程中调用,重绘当前 UI。Invalidate不能直接在线程中调用,由于他是违背了单线程模型:Android UI操做并非线程安全的,而且这些操做必须在UI线程中调用。

31)、Activity-Window-View三者的差异
这个问题真的很很差回答。因此这里先来个算是比较恰当的比喻来形容下它们的关系吧。Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。
1:Activity构造的时候会初始化一个Window,准确的说是PhoneWindow。
2:这个PhoneWindow有一个“ViewRoot”,这个“ViewRoot”是一个View或者说ViewGroup,是最初始的根视图。
3:“ViewRoot”经过addView方法来一个个的添加View。好比TextView,Button等
4:这些View的事件监听,是由WindowManagerService来接受消息,而且回调Activity函数。好比onClickListener,onKeyDown等。

32)、ActivityThread,AMS,WMS的工做原理
Activity与Window:
Activity只负责生命周期和事件处理
Window只控制视图
一个Activity包含一个Window,若是Activity没有Window,那就至关于Service。

33)、AMS与WMS:
AMS统一调度全部应用程序的Activity
WMS控制全部Window的显示与隐藏以及要显示的位置。在视图层次中,Activity在WIndow之上

ActivityThread:是Android应用的主线程(UI线程)

WMS(WindowManagerService):管理的整个系统全部窗口的UI
做用:
为全部窗口分配Surface:客户端向WMS添加一个窗口的过程,其实就是WMS为其分配一块Suiface的过程,一块块Surface在WMS的管理下有序的排布在屏幕上。Window的本质就是Surface。(简单的说Surface对应了一块屏幕缓冲区)
管理Surface的显示顺序、尺寸、位置
管理窗口动画
输入系统相关:WMS是派发系统按键和触摸消息的最佳人选,当接收到一个触摸事件,它须要寻找一个最合适的窗口来处理消息,而WMS是窗口的管理者,系统中全部的窗口状态和信息都在其掌握之中,完成这一工做不在话下。

AMS(ActivityManagerService)
ActivityManager是客户端用来管理系统中正在运行的全部Activity包括Task、Memory、Service等信息的工具。可是这些这些信息的维护工做却不是又ActivityManager负责的。在ActivityManager中有大量的get()方法,那么也就说明了他只是提供信息给AMS,由AMS去完成交互和调度工做。

做用:
统一调度全部应用程序的Activity的生命周期
启动或杀死应用程序的进程
启动并调度Service的生命周期
注册BroadcastReceiver,并接收和分发Broadcast
启动并发布ContentProvider
调度task
处理应用程序的Crash
查询系统当前运行状态

34)、自定义View如何考虑机型适配
布局类建议:
合理使用warp_content,match_parent.
尽量的是使用RelativeLayout
引入android的百分比布局。
针对不一样的机型,使用不一样的布局文
件放在对应的目录下,android会自动匹配。

35)、Icon类建议:
尽可能使用svg转换而成xml。
切图的时候切大分辨率的图,应用到布局当中。在小分辨率的手机上也会有很好的显示效果。
使用与密度无关的像素单位dp,sp

36)、AsyncTask 如何使用?
Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。
首先明确Android之因此有Handler和AsyncTask,都是为了避免阻塞主线程(UI线程),且UI的更新只能在主线程中完成,所以异步处理是不可避免的。
Android为了下降这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。

AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工做咱们要提供三个泛型参数,并重载几个方法(至少重载一个)。

例:

public class Task extends AsyncTask<void,void,void>//Void是三个泛型参数的原始状态,而且Void也是一个类而不是void

AsyncTask定义了三种泛型类型 Params,Progress和Result。

Params 启动任务执行的输入参数,好比HTTP请求的URL。(可传入多个参数)
Progress 后台任务执行的百分比。
Result 后台执行任务最终返回的结果,好比String。
使用过AsyncTask 的同窗都知道一个异步加载数据最少要重写如下这两个方法:

doInBackground(Params…) 后台执行,比较耗时的操做均可以放在这里。注意这里不能直接操做UI。此方法在后台线程执行,完成任务的主要工做,一般须要较长的时间。在执行过程当中能够调用publicProgress(Progress…)来更新任务的进度。
publicProgress(Progress…)会将Progress...传给onProgressUpdate(Progress...)做为ProgressUpdate(Progress...)的接收参数。
onPostExecute(Result) 至关于Handler 处理UI的方式,在这里面能够使用在doInBackground 获得的结果处理操做UI。 此方法在主线程执行,任务执行的结果做为此方法的参数返回
有必要的话你还得重写如下这三个方法,但不是必须的:

onProgressUpdate(Progress…) 能够使用进度条增长用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行以前开始调用此方法,能够在这里显示进度对话框。
onCancelled() 用户调用取消时,要作的操做
使用AsyncTask类,如下是几条必须遵照的准则:

Task的实例必须在UI thread(主线程)中建立;
execute方法必须在UI thread中调用;
不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
该task只能被执行一次,不然屡次调用时将会出现异常;

37)、SpareArray与HashMap比较,应用场景
SparseArray采用的不是哈希算法,HashMap采用的是哈希算法。
SparseArray采用的是两个一维数组分别用于存储键和值,HashMap采用的是一维数组+单向链表或二叉树。
SparseArray key只能是int类型,而HashMap的key是Object。
SparseArray key是有序存储(升序),而HashMap不是。
SparseArray 默认容量是10,而HashMap默认容量是16。
SparseArray 默认每次扩容是2倍于原来的容量,而HashMap默认每次扩容时是原容量*0.75倍
SparseArray value的存储被不像HashMap同样须要额外的须要一个实体类(Node)进行包装
SparseArray查找元素整体而言比HashMap要逊色,由于SparseArray查找是须要通过二分法的过程,而HashMap不存在冲突的状况其技术处的hash对应的下标直接就能够取到值。
针对上面与HashMap的比较,采用SparseArray仍是HashMap,建议根据以下需求选取:

若是对内存要求比较高,而对查询效率没什么大的要求,能够是使用SparseArray
数量在百级别的SparseArray比HashMap有更好的优点
要求key是int类型的,由于HashMap会对int自定装箱变成Integer类型
要求key是有序的且是升序

38)、请介绍下ContentProvider 是如何实现数据共享的?
一个程序能够经过实现一个Content provider的抽象接口将本身的数据彻底暴露出去,并且Content providers是以相似数据库中表的方式将数据暴露。Content providers存储和检索数据,经过它可让全部的应用程序访问到,这也是应用程序之间惟一共享数据的方法。
要想使应用程序的数据公开化,可经过2种方法:建立一个属于你本身的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型而且有写入Content provider的权限。
如何经过一套标准及统一的接口获取其余应用程序暴露的数据?
Android提供了ContentResolver,外界的程序能够经过ContentResolver接口访问ContentProvider提供的数据。

39)、AndroidService与Activity之间通讯的几种方式
经过 broadcast:经过广播发送消息到 activitry
经过 Binder:经过与 activity 进行绑定

40)、IntentService原理及做用是什么?
IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工做线程来处理耗时操做,启动IntentService的方式和启动传统Service同样,同时,当任务执行完后,IntentService会自动中止,而不须要咱们去手动控制。另外,能够启动IntentService屡次,而每个耗时操做会以工做队列的方式在IntentService的onHandleIntent回调方法中执行,而且,每次只会执行一个工做线程,执行完第一个再执行第二个,以此类推。
全部请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

41)、说说Activity、Intent、Service 是什么关系
一个 Activity 一般是一个单独的屏幕,每个 Activity 都被实现为一个单独的类,这些类都 是从 Activity 基类中继承来的, Activity 类会显示由视图控件组成的用户接口,并对视图控 件的事件作出响应。

Intent 的调用是用来进行架构屏幕之间的切换的。 Intent 是描述应用想要作什么。 Intent 数 据结构中两个最重要的部分是动做和动做 对应的数据, 一个动做对应一个动做数据。

Android Service 是运行在后台的代码,不能与用户交互,能够运行在本身的进程,也能够 运行在其余应用程序进程的上下文里。须要经过某一个 Activity 或者其余 Context 对象来调 用。 Activity 跳转到 Activity,Activity 启动 Service,Service 打开 Activity ,Activity 跳转到 Activity,Activity 启动 Service,Service 打开 Activity

SP是进程同步的吗?有什么方法作到同步?
SharedPreferences不支持进程同步
一个进程的状况,常常采用SharePreference来作,可是SharePreference不支持多进程,它基于单个文件的,默认是没有考虑同步互斥,并且,APP对SP对象作了缓存,很差互斥同步。

考虑用ContentProvider来实现SharedPreferences的进程同步,ContentProvider基于Binder,不存在进程间互斥问题,对于同步,也作了很好的封装,不须要开发者额外实现。另外ContentProvider的每次操做都会从新getSP,保证了sp的一致性。

42)、谈谈多线程在Android中的使用
Handler+Thread
AsyncTask
ThreadPoolExecutor
IntentService

43)、进程和 Application 的生命周期
onCreate():Application建立的时候调用
onConfigurationChanged(Configuration newConfig):当配置信息改变的时候会调用,如屏幕旋转、语言切换时。
onLowMemory():Android系统总体内存较低时候调用,一般在这里释放一些不重要的资源,或者提醒用户清一下垃圾,来保证内存足够而让APP进程不被系统杀掉。它和OnTrimMemory中的TRIM_MEMORY_COMPLETE级别相同。
onTrimMemory(int level):Android 4.0 以后提供的一个API,用于取代onLowMemory()。在系统内存不足的时会被调用,提示开发者清理部分资源来释放内存,从而避免被 Android 系统杀死。详见《Android代码内存优化建议-OnTrimMemory优化》
onTerminate():Application结束的时候会调用,由系统决定调用的时机

44)、封装View的时候怎么知道view的大小
这里考点是自定义的那几个方法含义,源码理解。须要本身去看看源码,而后用本身的话表达出来。

45)、AndroidManifest的做用与理解
AndroidManifest.xml 是每一个android程序中必须的文件。它位于整个项目的根目录,描述了package中暴露的组件(activities, services等等),他们各自的实现类,各类能被处理的数据和启动位置。 除了能声明程序中的Activities, ContentProviders, Services, 和Intent Receivers,还能指定permissions和instrumentation(安全控制和测试)。

46)、Handler、Thread和HandlerThread的差异
Handler:在Android中负责发送和处理消息,经过它能够实现其余支线线程与主线程之间的消通信
Thread:线程,能够看做是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的独立运行的基本单位
HandlerThread:封装了Handler + ThreadHandlerThread适合在有须要一个工做线程(非UI线程)+任务的等待队列的形式,优势是不会有堵塞,减小了对性能的消耗,缺点是不能同时进行多个任务的处理,须要等待进行处理。处理效率低,能够当成一个轻量级的线程池来用

47)、为何在主线程能够直接使用 Handler?
由于主线程已经建立了 Looper 对象并开启了消息循环

关于Handler,在任何地方new Handler 都是什么线程下?
不传递 Looper 建立 Handler:Handler handler = new Handler();上文就是 Handler 无参建立的源码,
能够看到是经过 Looper.myLooper() 来获取 Looper 对象,也就是说对于不传递 Looper 对象的状况下,
在哪一个线程建立 Handler 默认获取的就是该线程的 Looper 对象,那么 Handler 的一系列操做都是在该
线程进行的。

对于传递 Looper 对象建立 Handler 的状况下,传递的 Looper 是哪一个线程的,Handler 绑定的就是该线程。
ThreadLocal原理,实现及如何保证Local属性?
ThreadLocal:当某些数据是以线程为做用域而且不一样线程具备不一样的数据副本的时候,就能够考虑采用ThreadLocal。(Looper、ActivityThread以及AMS中都用到了),如使用ThreadLocal能够解决不一样线程不一样Looper的需求。

虽然在不一样线程中访问的是同一个ThreadLocal对象,可是它们经过ThreadLocal来获取到的值倒是不同的,这就是ThreadLocal的奇妙之处。ThreadLocal之因此有这么奇妙的效果,是由于不一样线程访问同一个ThreadLocal的get方法,ThreadLocal内部会从各自的线程中取出一个数组,而后再从数组中根据当前ThreadLocal的索引去查找出对应的value值,很显然,不一样线程中的数组是不一样的,这就是为何经过ThreadLocal能够在不一样的线程中维护一套数据的副本而且彼此互不干扰。(从ThreadLocal的set和get方法能够看出,它们所操做的对象都是当前线程的localValues对象的table数组,所以在不一样线程中访问同一个ThreadLocal的set和get方法,它们对ThreadLocal所作的读写操做仅限于各自线程的内部,这就是为何ThreadLocal能够在多个线程中互不干扰地存储和修改数据。)

Handler机制和底层实现

上面一共出现了几种类,ActivityThread,Handler,MessageQueue,Looper,msg(Message),对这些类做简要介绍:
ActivityThread:程序的启动入口,该类就是咱们说的主线程,它对Looper进行操做的。
Handler:字面意思是操控者,该类有比较重要的地方,就是经过handler来发送消息(sendMessage)到
MessageQueue和 操做控件的更新(handleMessage)。handler下面持有这MessageQueue和Looper的对象。
MessageQueue:字面意思是消息队列,就是封装Message类。对Message进行插入和取出操做。
Message:这个类是封装消息体并被发送到MessageQueue中的,给类是经过链表实现的,其好处方便MessageQueue的插入和取出操做。还有一些字段是(int what,Object obj,int arg1,int arg2)。what是用户定义的消息和代码,以便接收者(handler)知道这个是关于什么的。obj是用来传输任意对象的,arg1和arg2是用来传递一些简单的整数类型的。

先获取looper,若是没有就建立

建立过程:

ActivityThread 执行looperMainPrepare(),该方法先实例化MessageQueue对象,而后实例化Looper对象,封装mQueue和主线程,把本身放入ThreadLocal中

再执行loop()方法,里面会重复死循环执行读取MessageQueue。接着ActivityThread 执行Looper对象中的loop()方法)
此时调用sendMessage()方法,往MessageQueue中添加数据,其取出消息队列中的handler,执行dispatchMessage(),进而执行handleMessage(),Message的数据结构是基于链表的

Looper为何要无限循环?
主线程中若是没有looper进行循环,那么主线程一运行完毕就会退出。那么咱们还能运行APP吗,显然,这是不可能的,Looper主要就是作消息循环,而后由Handler进行消息分发处理,一旦退出消息循环,那么你的应用也就退出了。

主线程中的Looper.loop()一直无限循环为何不会形成ANR?
主线程Looper从消息队列读取消息,当读完全部消息时,主线程阻塞。子线程往消息队列发送消息,而且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。所以loop的循环并不会对CPU性能有过多的消耗。

请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系
Android中主线程是不能进行耗时操做的,子线程是不能进行更新UI的。因此就有了handler,它的做用就是实现线程之间的通讯。
handler整个流程中,主要有四个对象,handler,Message,MessageQueue,Looper。当应用建立的时候,就会在主线程中建立handler对象,
咱们经过要传送的消息保存到Message中,handler经过调用sendMessage方法将Message发送到MessageQueue中,Looper对象就会不断的调用loop()方法
不断的从MessageQueue中取出Message交给handler进行处理。从而实现线程之间的通讯。

48)、请描述一下View事件传递分发机制
Touch事件分发中只有两个主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件。View包含dispatchTouchEvent、onTouchEvent两个相关事件。其中ViewGroup又继承于View。
2.ViewGroup和View组成了一个树状结构,根节点为Activity内部包含的一个ViwGroup。
3.触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,能够为0个。
4.当Acitivty接收到Touch事件时,将遍历子View进行Down事件的分发。ViewGroup的遍历能够当作是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true。
5.当某个子View返回true时,会停止Down事件的分发,同时在ViewGroup中记录该子View。接下去的Move和Up事件将由该子View直接进行处理。因为子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:如ViewGroup0-ViewGroup1-TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,被保存在ViewGroup0中。当Move和UP事件来时,会先从ViewGroup0传递至ViewGroup1,再由ViewGroup1传递至TextView。
6.当ViewGroup中全部子View都不捕获Down事件时,将触发ViewGroup自身的onTouch事件。触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在全部子View都不处理的状况下,触发Acitivity的onTouchEvent方法。
7.onInterceptTouchEvent有两个做用:1.拦截Down事件的分发。2.停止Up和Move事件向目标View传递,使得目标View所在的ViewGroup捕获Up和Move事件。

事件分发中的onTouch 和onTouchEvent 有什么区别,又该如何使用?
OnTouch方法:
onTouch()是OnTouchListener接口的方法,它是获取某一个控件的触摸事件,所以使用时。经过getAction()方法能够获取当前触摸事件的状态:如:ACTION_DOWN:表示按下了屏幕的状态。

OnTouchEvent()方法:
onTouchEvent是手机屏幕事件的处理方法,是获取的对屏幕的各类操做,好比向左向右滑动,点击返回按钮等等。
经过查看安卓源码中View对dispatchTouchEvent的实现,能够知道onTouchListener(onTouch方法在其中)的接口的执行顺序是要先于onTouchEvent的,onTouch方法会先触发。

若是onTouchListener中的onTouch方法返回true,表示这次事件已经被消费了,那onTouchEvent是接收不到消息的。(内置诸如click事件的实现等等都基于onTouchEvent,这些事件将不会被触发),若是onTouch方法返回false会接着触发onTouchEvent。

View刷新机制
经过ViewRootImpl的scheduleTraversals()进行界面的三大流程。
调用到scheduleTraversals()时不会当即执行,而是将该操做保存到待执行队列中。并给底层的刷新信号注册监听。当VSYNC信号到来时,会从待执行队列中取出对应的scheduleTraversals()操做,并将其加入到主线程的消息队列中。
主线程从消息队列中取出并执行三大流程: onMeasure()-onLayout()-onDraw()

49)、View绘制流程
自定义控件:
一、组合控件。这种自定义控件不须要咱们本身绘制,而是使用原生控件组合成的新控件。如标题栏。
二、继承原有的控件。这种自定义控件在原生控件提供的方法外,能够本身添加一些方法。如制做圆角,圆形图片。
三、彻底自定义控件:这个View上所展示的内容所有都是咱们本身绘制出来的。好比说制做水波纹进度条。
View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw()
第一步:OnMeasure():测量视图大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。
第二步:OnLayout():肯定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所获得的布局大小和布局参数,将子View放在合适的位置上。
第三步:OnDraw():绘制视图。ViewRoot建立一个Canvas对象,而后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,若是没有就不用;
⑤、还原图层(Layer);⑥、绘制滚动条。

50)、自定义View如何提供获取View属性的接口?
自定义属性的实现流程: 
1.在values目录下定义一个attrs.xml :在res/values/attr.xml中定义相关属性。
2.在对应的类文件里生成某些组件 :在对应类的构造函数中经过 obtainStyledAttributes()方法得到自定义属性的相关值
3.在layout布局文件里为这些属性赋值:在布局中添加为该自定义组件设置一个命名空间,而且相关属性赋值

51)、AsyncTask是什么?
AsyncTask使得能够恰当和简单地使用 UI线程。这个class容许你在后台作一些事情,而后把进度和结果告诉UI线程,而不须要操做handler和线程。

52)、AsyncTask设计的思想是什么?
AsyncTask的设计是为了成为一个关于Thread和Handler的帮助类,并非一个通用的线程框架。AsyncTask理想状况下,应该被使用于很是短的操做(最多几秒)。若是您但愿您的线程能够运行很长时间,很是建议您使用java.util.concurrent包里面的API。例如Executor,ThreadPoolExecutor 和FutureTask

AsyncTask原理及不足
原理:
AsyncTask是Android自己提供的一种轻量级的异步任务类。它能够在线程池中执行后台任务,而后把执行的进度和最终的结果传递给主线程更新UI。实际上,AsyncTask内部是封装了Thread和Handler。虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,可是,AsyncTask并不合适进行特别耗时的后台操做,对于特别耗时的任务,我的仍是建议使用线程池。
AsyncTask提供有4个核心方法:
一、onPreExecute():该方法在主线程中执行,在执行异步任务以前会被调用,通常用于一些准备工做。
二、doInBackground(String... params):这个方法是在线程池中执行,此方法用于执行异步任务。在这个方法中能够经过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法,另外,任务的结果返回给onPostExecute方法。
三、onProgressUpdate(Object... values):该方法在主线程中执行,主要用于任务进度更新的时候,该方法会被调用。
四、onPostExecute(Long aLong):在主线程中执行,在异步任务执行完毕以后,该方法会被调用,该方法的参数及为后台的返回结果。
除了这几个方法以外还有一些不太经常使用的方法,如onCancelled(),在异步任务取消的状况下,该方法会被调用。
源码能够知道从上面的execute方法内部调用的是executeOnExecutor()方法,即executeOnExecutor(sDefaultExecutor, params);而sDefaultExecutor其实是一个串行的线程池。而onPreExecute()方法在这里就会被调用了。接着看这个线程池。AsyncTask的执行是排队执行的,由于有关键字synchronized,而AsyncTask的Params参数就封装成为FutureTask类,FutureTask这个类是一个并发类,在这里它充当了Runnable的做用。接着FutureTask会交给SerialExecutor的execute方法去处理,而SerialExecutor的executor方法首先就会将FutureTask添加到mTasks队列中,若是这个时候没有任务,就会调用scheduleNext()方法,执行下一个任务。若是有任务的话,则执行完毕后最后在调用 scheduleNext();执行下一个任务。直到全部任务被执行完毕。而AsyncTask的构造方法中有一个call()方法,而这个方法因为会被FutureTask的run方法执行。因此最终这个call方法会在线程池中执行。而doInBackground这个方法就是在这里被调用的。咱们好好研究一下这个call()方法。mTaskInvoked.set(true);表示当前任务已经执行过了。接着执行doInBackground方法,最后将结果经过postResult(result);方法进行传递。postResult()方法中经过sHandler来发送消息,sHandler的中经过消息的类型来判断一个MESSAGE_POST_RESULT,这种状况就是调用onPostExecute(result)方法或者是onCancelled(result)。另外一种消息类型是MESSAGE_POST_PROGRESS则调用更新进度onProgressUpdate。

不足:AsyncTask的优势在于执行完后台任务后能够很方便的更新UI,然而使用它存在着诸多的限制。先抛开内存泄漏问题,使用AsyncTask主要存在如下局限性:
在Android 4.1版本以前,AsyncTask类必须在主线程中加载,这意味着对AsyncTask类的第一次访问必须发生在主线程中;在Android 4.1以及以上版本则不存在这一限制,由于ActivityThread(表明了主线程)的main方法中会自动加载AsyncTask 
AsyncTask对象必须在主线程中建立 
AsyncTask对象的execute方法必须在主线程中调用 
一个AsyncTask对象只能调用一次execute方法

53)、如何取消AsyncTask?
1.调用cancel():可是他是在在doInBackground()以后执行

若是调用cancel()方法,它不会当即执行,只有当doInBackground()方法执行完有返回值以后,会在UI主线程调用cancel(),同时也会间接的调用iscancelled(),而且返回true ,这个时候就不会再调onPostExecute(),而后在doInBackground()里按期检查iscancelled()方法的返回值,是否被cancel,若是return true,就尽快中止。

2.在耗时操做中设置一些flag:咱们能够在这个线程中的耗时操做中设置一些flag,也就是AsyncTask的doInBackground方法中的某些关键步骤。
而后在外层须要终止此线程的地方改变这个flag值,线程中的耗时代码一步步执行,当某一时刻发现flag的值变了,throwException,线程就不会再继续执行了。为了保险起见,在外层咱们还要捕获这个异常,进行相应处理。(子线程被发生异常后会本身死掉而不会引发其余问题,更不会影响到主线程,更况且咱们为了更加安全还捕获了异常并作处理)

54)、AsyncTask适合作什么?
必须同时知足如下条件:
a.执行过程单一,仅输入一次,输出一次。
b.花费时间很是短可是仍然须要到后台去作事情,而后更新UI。例如加载文件,web页面或者数据库到UI。
c.执行线程必须是UI线程
d.不须要长期维护状态。

55)、AsyncTask不适合作什么?
a.长时间的任务。
b.可重复调用的任务。
c.须要线程执行多个不一样任务,任务之间又有关联。
d.执行线程不是UI线程。
e.任务执行后仍然须要维护一些状态。
f.后台服务模块,须要提供独立的API.

56)、为何不能在子线程更新UI?
目的在于提升移动端更新UI的效率和和安全性,以此带来流畅的体验。缘由是:
Android的UI访问是没有加锁的,多个线程能够同时访问更新操做同一个UI控件。也就是说访问UI的时候,android系统当中的控件都不是线程安全的,这将致使在多线程模式下,当多个线程共同访问更新操做同一个UI控件时容易发生不可控的错误,而这是致命的。因此Android中规定只能在UI线程中访问UI,这至关于从另外一个角度给Android的UI访问加上锁,一个伪锁。
57)、ANR产生的缘由是什么?
ANR即Application Not Responding,顾名思义就是应用程序无响应。

在Android中,通常状况下,四大组件均是工做在主线程中的,Android中的Activity Manager和Window Manager会随时监控应用程序的响应状况,若是由于一些耗时操做(网络请求或者IO操做)形成主线程阻塞必定时间(例如形成5s内不能响应用户事件或者BroadcastReceiver的onReceive方法执行时间超过10s),那么系统就会显示ANR对话框提示用户对应的应用处于无响应状态。

  1. 不要让主线程干耗时的工做
  2. 不要让其余线程阻塞主线程的执行

ANR定位和修正
ANR通常有三种类型
KeyDispatchTimeout(5 seconds) –主要类型
按键或触摸事件在特定时间内无响应
BroadcastTimeout(10 seconds)
BroadcastReceiver在特定时间内没法处理完成
ServiceTimeout(20 seconds) –小几率类型
Service在特定的时间内没法处理完成

一、主线程当中执行IO/网络操做,容易阻塞。二、主线程当中执行了耗时的计算。(好比自定义控件中的onDraw()方法)在onDraw()方法里面建立对象容易致使内存抖动(绘制动做时会大量不间断调用,产生大量垃圾对象致使GC很频繁,就形成了内存抖动),内存抖动就容易形成UI出现掉帧、卡顿等问题。三、BroadCastReceiver没有在10秒内完成处理。四、BroadCastReceiver的onReceived代码中也要尽可能减小耗时的操做,建议使用IntentService处理。五、Service执行了耗时的操做,由于Service也是在主线程当中执行的,因此耗时操做应该在Service里面开启子线程来作。六、使用AsyncTask处理耗时的IO等操做。七、Activity的onCreate和onResume回调中尽可能耗时的操做。

相关文章
相关标签/搜索