小总结:
http://www.jianshu.com/p/89f19d67b348
https://github.com/stormzhang/android-interview-questions-cn#android-%E6%A0%B8%E5%BF%83
看到如此多的MVP+Dagger2+Retrofit+Rxjava项目,轻松拿star,心动了吗?
http://www.jianshu.com/p/4bbecd0bb027
从Android代码中来记忆23种设计模式
http://www.jianshu.com/p/1a9f571ad7c0
http://www.jianshu.com/u/f9fbc7a39b36
插件化
http://www.jianshu.com/p/353514d315a7
横竖屏切换时候Activity的生命周期
不设置Activity的android:configChanges时,切屏会重新回掉各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
设置Activity的android:configChanges=”orientation”时,切屏还是会调用各个生命周期,切换横竖屏只会执行一次
设置Activity的android:configChanges=”orientation |keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
AsyncTask
源码解析
AsyncTask的缺陷和问题
关于线程池:asynctask对应的线程池ThreadPoolExecutor都是进程范围内共享的,都是static的,所以是asynctask控制着进程范围内所有的子类实例。由于这个限制的存在,当使用默认线程池时,如果线程数超过线程池的最大容量,线程池就会爆掉(3.0后默认串行执行,不会出现这个问题)。针对这种情况,可以尝试自定义线程池,配合asynctask使用。
关于默认线程池:核心线程池中最多有CPU_COUNT+1个,最多有CPU_COUNT*2+1个,线程等待队列的最大等待数为128,但是可以自定义线程池。线程池是由AsyncTask来管理的,线程池允许tasks并行运行,需要注意的是并发情况下数据的一致性问题,新数据可能会被老数据覆盖掉,类似volatile变量。所以希望tasks能够串行运行的话,使用SERIAL_EXECUTOR。
Acitivty的任务栈
使用android:launchMode="standard|singleInstance|single Task|singleTop"来控制Acivity任务栈。
任务栈是一种后进先出的结构。位于栈顶的Activity处于焦点状态,当按下back按钮的时候,栈内的Activity会一个一个的出栈,并且调用其onDestory()方法。如果栈内没有Activity,那么系统就会回收这个栈,每个APP默认只有一个栈,以APP的包名来命名.
- standard : 标准模式,每次启动Activity都会创建一个新的Activity实例,并且将其压入任务栈栈顶,而不管这个Activity是否已经存在。Activity的启动三回调(onCreate()->onStart()->onResume())都会执行。
- singleTop : 栈顶复用模式.这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,所以它的启动三回调就不会执行,同时Activity的onNewIntent()方法会被回调.如果Activity已经存在但是不在栈顶,那么作用于standard模式一样.
- singleTask: 栈内复用模式.创建这样的Activity的时候,系统会先确认它所需任务栈已经创建,否则先创建任务栈.然后放入Activity,如果栈中已经有一个Activity实例,那么这个Activity就会被调到栈顶,onNewIntent(),并且singleTask会清理在当前Activity上面的所有Activity.(clear top)
- singleInstance : 加强版的singleTask模式,这种模式的Activity只能单独位于一个任务栈内,由于栈内复用的特性,后续请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了
Activity的堆栈管理以ActivityRecord为单位,所有的ActivityRecord都放在一个List里面.可以认为一个ActivityRecord就是一个Activity栈
onSaveInstanceState() 与onRestoreIntanceState()
用户或者程序员主动去销毁一个Activity的时候不会掉用,其他情况都会调动,来保存界面信息。如代码中finish()或用户按下back,不会掉用。
android中进程的优先级?
- 前台进程:即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最后被杀死的
- 可见进程:可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失去了焦点而不能与用户交互
- 服务进程:其中运行着使用startService方法启动的Service,虽然不被用户可见,但是却是用户关心的,例如用户正在非音乐界面听的音乐或者正在非下载页面自己下载的文件等;当系统要空间运行前两者进程时才会被终止
- 后台进程:其中运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这样的进程系统一旦没了有内存就首先被杀死
- 空进程:不包含任何应用程序的程序组件的进程,这样的进程系统是一般不会让他存在的
Serializable和Parcelable
序列化,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
- Serializable(Java自带):
Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。 - Parcelable(android 专用):
除了Serializable之外,使用Parcelable也可以实现相同的效果,
不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,
而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
动画
- tween 补间动画。通过指定View的初末状态和变化时间、方式,对View的内容完成一系列的图形变换来实现动画效果。 Alpha, Scale ,Translate, Rotate。
- frame 帧动画 AnimationDrawable 控制 animation-list xml布局
- PropertyAnimation 属性动画 3.0引入,属性动画核心思想是对值的变化。
属性动画
详解
Property Animation 动画有两个步聚:
1.计算属性值
2.为目标对象的属性设置属性值,即应用和刷新动画
计算属性分为3个过程:
- 过程一:计算已完成动画分数 elapsed fraction 为了执行一个动画,你需要创建一个 ValueAnimator,并且指定目标对象属性的开始、结束值和持续时间。在调用 start 后的整个动画过程中, ValueAnimator 会根据已经完成的动画时间计算得到一个 0 到 1 之间的分数,代表该动画的已完成动画百分比。0 表示 0%,1 表示 100%。
- 过程二:计算插值(动画变化率)interpolated fraction 当 ValueAnimator 计算完已完成动画分数后,它会调用当前设置的 TimeInterpolator,去计算得到一个 interpolated(插值)分数,在计算过程中,已完成动画百分比会被加入到新的插值计算中。
- 过程三:计算属性值 当插值分数计算完成后,ValueAnimator 会根据插值分数调用合适的 TypeEvaluator 去计算运动中的属性值。
以上分析引入了两个概念:已完成动画分数(elapsed fraction)、插值分数( interpolated fraction )。
Android的数据存储形式
- SQLite:SQLite是一个轻量级的数据库,支持基本的SQL语法,是常被采用的一种数据存储方式。 Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的api
- SharedPreference: 以键值对的形势储存。其本质就是一个xml文件,常用于存储较简单的参数设置。
- File: 即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的事情。
- ContentProvider: Android系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。每个Content Provider都会对外提供一个公共的URI(包装成Uri对象),如果应用程序有数据需要共享时,就需要使用Content Provider为这些数据定义一个URI,然后其他的应用程序就通过Content Provider传入这个URI来对数据进行操作。
Context相关
Activity和Service以及Application的Context是不一样的,Activity继承自ContextThemeWraper.其他的继承自ContextWrapper.
每一个Activity和Service以及Application的Context都是一个新的ContextImpl对象
getApplication()用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法,getApplicationContext()比getApplication()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。
创建Toast和对话框不可以用Application 的context,只能用Activity的context。
Context的数量等于Activity的个数 + Service的个数 + 1,这个1为Application
Android各版本新特性
Android5.0新特性
- MaterialDesign设计风格
- 支持多种设备
- 支持64位ART虚拟机
Android6.0新特性
- 大量漂亮流畅的动画
- 支持快速充电的切换
- 支持文件夹拖拽应用
- 相机新增专业模式
Android7.0新特性
- 分屏多任务
- 增强的Java8语言模式
- 夜间模式
Json
- JSON的全程是JavaScript Object Notation,也就是JavaScript 对象表示法
- JSON是存储和交换文本信息的语法,类似XML,但是比XML更小、更快,更易解析
- JSON是轻量级的文本数据交换格式,独立于语言,具有自我描述性,更易理解
对象可以包含多个名称/值对,比如:
{"name":"zhangsan" , "age":25}
使用谷歌的GSON包进行解析
在 Android Studio 里引入依赖:
compile 'com.google.code.gson:gson:2.7'
值得注意的是实体类中变量名称必须和json中的值名相同。
json1的解析
我们这里的实体类是Student.class
Gson gson = new Gson();
Student student = gson.fromJson(json1, Student.class);
json2的解析
我们可以解析成int数组,也可以解析成Integer的List。
解析成数组:
Gson gson = new Gson();
int[] ages = gson.fromJson(json2, int[].class);
解析成List:
Gson gson = new Gson();
List<Integer> ages = gson.fromJson(json2, new TypeToken<List<Integer>>(){}.getType);
json3的解析
同样可以解析成List或者数组,我们就直接解析成List.
Gson gson = new Gson();
List<Student> students = gson.fromJson(json3, new TypeToke<List<Student>>(){}.getType);
android中有哪几种解析xml的类,官方推荐哪种?以及它们的原理和区别
- DOM解析
优点:
1.XML树在内存中完整存储,因此可以直接修改其数据和结构.
2.可以通过该解析器随时访问XML树中的任何一个节点.
3.DOM解析器的API在使用上也相对比较简单.
缺点:如果XML文档体积比较大时,将文档读入内存是非常消耗系统资源的.
使用场景:DOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准.DOM 是以层次结构组织的节点的集合.这个层次结构允许开发人员在树中寻找特定信息.分析该结构通常需要加载整个文档和构造层次结构,然后才能进行任何工作.DOM是基于对象层次结构的. - SAX解析
优点:
SAX 对内存的要求比较低,因为它让开发人员自己来决定所要处理的标签.特别是当开发人员只需要处理文档中所包含的部分数据时,SAX 这种扩展能力得到了更好的体现.
缺点:
用SAX方式进行XML解析时,需要顺序执行,所以很难访问到同一文档中的不同数据.此外,在基于该方式的解析编码过程也相对复杂.
使用场景:
对于含有数据量十分巨大,而又不用对文档的所有数据进行遍历或者分析的时候,使用该方法十分有效.该方法不用将整个文档读入内存,而只需读取到程序所需的文档标签处即可. - Xmlpull解析
android SDK提供了xmlpull api,xmlpull和sax类似,是基于流(stream)操作文件,然后根据节点事件回调开发者编写的处理程序.因为是基于流的处理,因此xmlpull和sax都比较节约内存资源,不会象dom那样要把所有节点以对橡树的形式展现在内存中.xmlpull比sax更简明,而且不需要扫描完整个流.
Jar和Aar的区别
Jar包里面只有代码,aar里面不光有代码还包括代码还包括资源文件,比如 drawable 文件,xml 资源文件。对于一些不常变动的 Android Library,我们可以直接引用 aar,加快编译速度
什么是三级缓存
(研究中)
三级缓存原理
(研究中)
Android为每个应用程序分配的内存大小是多少
android程序内存一般限制在16M,也有的是24M
引起内存泄漏的情况
- 对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销。
- 静态内部类持有外部成员变量(或context):可以使用弱引用或使用ApplicationContext。
- 内部类持有外部类引用,异步任务中,持有外部成员变量。
- 集合中没用的对象没有及时remove。
- 不用的对象及时释放,如使用完Bitmap后掉用recycle(),再赋null。
- handler引起的内存泄漏,MessageQueue里的消息如果在activity销毁时没有处理完,就会引起内存的泄漏,可以使用弱引用解决。
- 设置过的监听不用时,及时移除。如在Destroy时及时remove。尤其以addListener开头的,在Destroy中都需要remove。
- activity泄漏可以使用LeakCanary。
- 在内存引用上做些处理,常用的有软引用、弱引用
- 在内存中加载图片时直接在内存中作处理,如:边界压缩
- 动态回收内存
- 优化Dalvik虚拟机的堆内存分配
- 自定义堆内存大小
Activity/Window/View三者的差别,fragment的特点
Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutInflater像剪刀,Xml配置像窗花图纸。
在Activity中调用attach,创建了一个Window
创建的window是其子类PhoneWindow,在attach中创建PhoneWindow
在Activity中调用setContentView(R.layout.xxx)
其中实际上是调用的getWindow().setContentView()
调用PhoneWindow中的setContentView方法
创建ParentView:
作为ViewGroup的子类,实际是创建的DecorView(作为FramLayout的子类)
将指定的R.layout.xxx进行填充
通过布局填充器进行填充【其中的parent指的就是DecorView】
调用到ViewGroup
调用ViewGroup的removeAllView(),先将所有的view移除掉
添加新的view:addView()
Fragment 特点
Fragment可以作为Activity界面的一部分组成出现;
可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用;
在Activity运行过程中,可以添加、移除或者替换Fragment;
Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。
JVM 和Dalvik虚拟机的区别
- JVM:
.java -> javac -> .class -> jar -> .jar
架构: 堆和栈的架构. - DVM:
.java -> javac -> .class -> dx.bat -> .dex
架构: 寄存器(cpu上的一块高速缓存)
怎么考虑数据传输的安全性
如果应用对传输的数据没有任何安全措施,攻击者设置的钓鱼网络中更改DNS服务器。这台服务器可以获取用户信息,或充当中间人与原服务器交换数据。在SSL/TLS通信中,客户端通过数字证书判断服务器是否可信,并采用证书的公钥与服务器进行加密通信。