亲爱的面试官,这个我可没看过!(Android部分)

来源:互联网 发布:蓝海智投 知乎 编辑:程序博客网 时间:2024/05/16 12:24

http://www.jianshu.com/p/89f19d67b348#

导读:Android面试中高频率出现的题都在这了。试题大部分从互联网收集,博主下了一番功夫进行梳理总结,难免有不足之处,还请见谅。这篇博客属于Androi,你够了!!!专题中的一篇,其余文章会陆续发表,第一时间会发布在本人Github上,敬请关注。这篇博客包括五个部分:热点,基础,进阶,性能优化,高级。后续会不断补充完善,希望能为小伙伴们找工作增加点自信��。
题库收集整理的周期比较长,很多原作者的链接没有了,非常抱歉。如果文章中用到了您的内容,请在下面留言.
浪子潇涧的面试总结
推荐:清华浪子潇涧的面试总结--面试大礼包
热点

如何保证Service不被杀死

Android 进程不死从3个层面入手:

A.提供进程优先级,降低进程被杀死的概率
方法一:监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,在用户解锁时将 Activity 销毁掉。
方法二:启动前台service。
方法三:提升service优先级:
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
B. 在进程被杀死后,进行拉活
方法一:注册高频率广播接收器,唤起进程。如网络变化,解锁屏幕,开机等
方法二:双进程相互唤起。
方法三:依靠系统唤起。
方法四:onDestroy方法里重启service:service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
C. 依靠第三方
根据终端不同,在小米手机(包括 MIUI)接入小米推送、华为手机接入华为推送;其他手机可以考虑接入腾讯信鸽或极光推送与小米推送做 A/B Test。
参考博客:Android 进程保活招式大全

ButterKnife原理
ButterKnife对性能的影响很小,因为没有使用使用反射,而是使用的Annotation Processing Tool(APT),注解处理器,javac中用于编译时扫描和解析Java注解的工具。在编译阶段执行的,它的原理就是读入Java源代码,解析注解,然后生成新的Java代码。新生成的Java代码最后被编译成Java字节码,注解解析器不能改变读入的Java 类,比如不能加入或删除Java方法。

参考资料:
最新ButterKnife框架原理
Java Annotation 及几个常用开源项目注解原理简析
ButterKnife 简单原理实现

基础

Activity和Fragment生命周期有哪些?

屏幕快照 2016-09-19 下午8.10.27.png
横竖屏切换时候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。

AsyncTask在不同的SDK版本中的区别:
调用AsyncTask的excute方法不能立即执行程序的原因分析及改善方案
通过查阅官方文档发现,AsyncTask首次引入时,异步任务是在一个独立的线程中顺序的执行,也就是说一次只能执行一个任务,不能并行的执行,从1.6开始,AsyncTask引入了线程池,支持同时执行5个异步任务,也就是说同时只能有5个线程运行,超过的线程只能等待,等待前面的线程某个执行完了才被调度和运行。换句话说,如果一个进程中的AsyncTask实例个数超过5个,那么假如前5个都运行很长时间的话,那么第6个只能等待机会了。这是AsyncTask的一个限制,而且对于2.3以前的版本无法解决。如果你的应用需要大量的后台线程去执行任务,那么你只能放弃使用AsyncTask,自己创建线程池来管理Thread。不得不说,虽然AsyncTask较Thread使用起来方便,但是它最多只能同时运行5个线程,这也大大局限了它的实力,你必须要小心设计你的应用,错开使用AsyncTask的时间,尽力做到分时,或者保证数量不会大于5个,否则就会遇到上次提到的问题。可能是Google意识到了AsyncTask的局限性了,从Android3.0开始对AsyncTask的API作出了一些调整:每次只启动一个线程执行一个任务,完成之后再执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务。

1.生命周期
很多开发者会认为一个在Activity中创建的AsyncTask会随着Activity的销毁而销毁。然而事实并非如此。AsyncTask会一直执行,直到doInBackground()方法执行完毕。然后,如果cancel(boolean)被调用,那么onCancelled(Result result)方法会被执行;否则,执行onPostExecute(Result result)方法。如果我们的Activity销毁之前,没有取消AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。因为它想要处理的view已经不在了。所以,我们总是必须确保在销毁活动之前取消任务。总之,我们使用AsyncTask需要确保AsyncTask正确的取消。
2.内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄漏。
3.结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
4.并行还是串行
在Android1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了 修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要执行executeOnExecutor(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.为目标对象的属性设置属性值,即应用和刷新动画

valuecaculate.png

计算属性分为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 ages = gson.fromJson(json2, new TypeToken

阅读全文
0 0
原创粉丝点击