虽然本人不搞Android了,可是对于Android仍是时常关注的,这里根据网上的资料对2018的Android面试作一个总结。 一、Activity生命周期? Android的生命周期主要有七个,按其建立到销毁主要有如下几个阶段:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()java
二、Service生命周期?linux
service 启动方式有两种,一种是经过startService()方式进行启动,另外一种是经过bindService()方式进行启动。不一样的启动方式他们的生命周期是不同.android
经过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,须要注意一下几个问题,第一:当咱们经过startService被调用之后,屡次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被屡次调用当咱们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当咱们经过startService启动时候,经过intent传值,在onStartConmon()方法中获取值的时候,必定要先判断intent是否为null。ios
经过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 这种方式进行启动service好处是更加便利activity中操做service,好比加入service中有几个方法,a,b ,若是要在activity中调用,在须要在activity获取ServiceConnection对象,经过ServiceConnection来获取service中内部类的类对象,而后经过这个类对象就能够调用类中的方法,固然这个类须要继承Binder对象。面试
三、Activity的启动过程算法
app启动的过程有两种状况,第一种是从桌面launcher上点击相应的应用图标,第二种是在activity中经过调用startActivity来启动一个新的activity。设计模式
咱们建立一个新的项目,默认的根activity都是MainActivity,而全部的activity都是保存在堆栈中的,咱们启动一个新的activity就会放在上一个activity上面,而咱们从桌面点击应用图标的时候,因为launcher自己也是一个应用,当咱们点击图标的时候,系统就会调用startActivitySately(),通常状况下,咱们所启动的activity的相关信息都会保存在intent中,好比action,category等等。api
咱们在安装这个应用的时候,系统也会启动一个PackaManagerService的管理服务,这个管理服务会对AndroidManifest.xml文件进行解析,从而获得应用程序中的相关信息,好比service,activity,Broadcast等等,而后得到相关组件的信息。当咱们点击应用图标的时候,就会调用startActivitySately()方法,而这个方法内部则是调用startActivty(),而startActivity()方法最终仍是会调用startActivityForResult()这个方法。而在startActivityForResult()这个方法。由于startActivityForResult()方法是有返回结果的,因此系统就直接给一个-1,就表示不须要结果返回了。数组
而startActivityForResult()这个方法实际是经过Instrumentation类中的execStartActivity()方法来启动activity,Instrumentation这个类主要做用就是监控程序和系统之间的交互。而在这个execStartActivity()方法中会获取ActivityManagerService的代理对象,经过这个代理对象进行启动activity。启动会就会调用一个checkStartActivityResult()方法,若是说没有在配置清单中配置有这个组件,就会在这个方法中抛出异常了。浏览器
固然最后是调用的是Application.scheduleLaunchActivity()进行启动activity,而这个方法中经过获取获得一个ActivityClientRecord对象,而这个ActivityClientRecord经过handler来进行消息的发送,系统内部会将每个activity组件使用ActivityClientRecord对象来进行描述,而ActivityClientRecord对象中保存有一个LoaderApk对象,经过这个对象调用handleLaunchActivity来启动activity组件,而页面的生命周期方法也就是在这个方法中进行调用。
四、Broadcast注册方式与区别?什么状况下用动态注册?
Broadcast广播,注册方式主要有两种.
第一种是静态注册,也可成为常驻型广播,这种广播须要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即便退出了页面,也能够收到广播这种广播通常用于想开机自启动啊等等,因为这种注册的方式的广播是常驻型广播,因此会占用CPU的资源。
第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫很是驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,咱们一般运用在更新UI方面。这种注册方式优先级较高。最后须要解绑,否会会内存泄露
广播是分为有序广播和无序广播。
五、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。
六、java虚拟机和Dalvik虚拟机的区别
Java虚拟机:
一、java虚拟机基于栈。 基于栈的机器必须使用指令来载入和操做栈上数据,所需指令更多更多。
二、java虚拟机运行的是java字节码。(java类会被编译成一个或多个字节码.class文件)
Dalvik虚拟机:
一、dalvik虚拟机是基于寄存器的
二、Dalvik运行的是自定义的.dex字节码格式。(java类被编译成.class文件后,会经过一个dx工具将全部的.class文件转换成一个.dex文件,而后dalvik虚拟机会从其中读取指令和数据
三、常量池已被修改成只使用32位的索引,以简化解释器。
四、一个应用,一个虚拟机实例,一个进程(全部android应用的线程都是对应一个linux线程,都运行在本身的沙盒中,不一样的应用在不一样的进程中运行。每一个android dalvik应用程序都被赋予了一个独立的linux PID(app_*))
七、系统怎么进程保活(不死进程)
此处延伸:进程的优先级是什么
当前业界的Android进程保活手段主要分为** 黑、白、灰 **三种,其大体的实现思路以下:
黑色保活:不一样的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)
白色保活:启动前台Service
灰色保活:利用系统的漏洞启动前台Service
黑色保活
所谓黑色保活,就是利用不一样的app进程使用广播来进行相互唤醒。举个3个比较常见的场景:
场景1:开机,网络切换、拍照、拍视频时候,利用系统产生的广播唤醒app
场景2:接入第三方SDK也会唤醒相应的app进程,如微信sdk会唤醒微信,支付宝sdk会唤醒支付宝。由此发散开去,就会直接触发了下面的 场景3
场景3:假如你手机里装了支付宝、淘宝、天猫、UC等阿里系的app,那么你打开任意一个阿里系的app后,有可能就顺便把其余阿里系的app给唤醒了。(只是拿阿里打个比方,其实BAT系都差很少)
白色保活
白色保活手段很是简单,就是调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着,哪怕当前的app退到了后台。以下方的LBE和QQ音乐这样:
灰色保活
灰色保活,这种保活手段是应用范围最普遍。它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程同样。这样作带来的好处就是,用户没法察觉到你运行着一个前台进程(由于看不到Notification),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢,大体的实现思路和代码以下:
思路一:API < 18,启动前台Service时直接传入new Notification();
思路二:API >= 18,同时启动两个id相同的前台Service,而后再将后启动的Service作stop处理
熟悉Android系统的童鞋都知道,系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在系统内存不足的状况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给须要的app。这套杀进程回收内存的机制就叫 Low Memory Killer ,它是基于Linux内核的 OOM Killer(Out-Of-Memory killer)机制诞生。
进程的重要性,划分5级:
前台进程 (Foreground process)
可见进程 (Visible process)
服务进程 (Service process)
后台进程 (Background process)
空进程 (Empty process)
了解完 Low Memory Killer,再科普一下oom_adj。什么是oom_adj?它是linux内核分配给每一个系统进程的一个值,表明进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收。对于oom_adj的做用,你只须要记住如下几点便可:
进程的oom_adj越大,表示此进程优先级越低,越容易被杀回收;越小,表示进程优先级越高,越不容易被杀回收
普通app进程的oom_adj>=0,系统进程的oom_adj才可能<0
有些手机厂商把这些知名的app放入了本身的白名单中,保证了进程不死来提升用户体验(如微信、QQ、陌陌都在小米的白名单中)。若是从白名单中移除,他们终究仍是和普通app同样躲避不了被杀的命运,为了尽可能避免被杀,仍是老老实实去作好优化工做吧。
因此,进程保活的根本方案终究仍是回到了性能优化上,进程永生不死终究是个彻头彻尾的伪命题!
八、讲解一下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)
九、理解Activity,View,Window三者关系
这个问题真的很很差回答。因此这里先来个算是比较恰当的比喻来形容下它们的关系吧。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等。
十、四种LaunchMode及其使用场景
此处延伸:栈(First In Last Out)与队列(First In First Out)的区别
栈与队列的区别:
队列先进先出,栈先进后出
对插入和删除操做的"限定"。 栈是限定只能在表的一端进行插入和删除操做的线性表。 队列是限定只能在表的一端进行插入和在另外一端进行删除操做的线性表。
遍历数据速度不一样
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。
十一、简述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);⑥、绘制滚动条。
十二、View,ViewGroup事件分发
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事件。
1三、保存Activity状态
onSaveInstanceState(Bundle)会在activity转入后台状态以前被调用,也就是onStop()方法以前,onPause方法以后被调用;
1四、Android中的几种动画
帧动画:指经过指定每一帧的图片和播放时间,有序的进行播放而造成动画效果,好比想听的律动条。
补间动画:指经过指定View的初始状态、变化时间、方式,经过一系列的算法去进行图形变换,从而造成动画效果,主要有Alpha、Scale、Translate、Rotate四种效果。注意:只是在视图层实现了动画效果,并无真正改变View的属性,好比滑动列表,改变标题栏的透明度。
属性动画:在Android3.0的时候才支持,经过不断的改变View的属性,不断的重绘而造成动画效果。相比于视图动画,View的属性是真正改变了。好比view的旋转,放大,缩小。
1五、Android中跨进程通信的几种方式 Android 跨进程通讯,像intent,contentProvider,广播,service,Socket均可以跨进程通讯。
intent:这种跨进程方式并非访问内存的形式,它须要传递一个uri,好比说打电话。
contentProvider:这种形式,是使用数据共享的形式进行数据共享。
service:远程服务,aidl
广播
1六、AIDL理解,并简述Binder机制
AIDL: 每个进程都有本身的Dalvik VM实例,都有本身的一块独立的内存,都在本身的内存上存储本身的数据,执行着本身的操做,都在本身的那片狭小的空间里过完本身的一辈子。而aidl就相似与两个进程之间的桥梁,使得两个进程之间能够进行数据的传输,跨进程通讯有多种选择,好比 BroadcastReceiver , Messenger 等,可是 BroadcastReceiver 占用的系统资源比较多,若是是频繁的跨进程通讯的话显然是不可取的;Messenger 进行跨进程通讯时请求队列是同步进行的,没法并发执行。
Binder机制简单理解:
在Android系统的Binder机制中,是有Client,Service,ServiceManager,Binder驱动程序组成的,其中Client,service,Service Manager运行在用户空间,Binder驱动程序是运行在内核空间的。而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,Service Manager提供辅助管理的功能,而Client和Service正是在Binder驱动程序和Service Manager提供的基础设施上实现C/S 之间的通讯。其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互,
Client、Service,Service Manager经过open和ioctl文件操做相应的方法与Binder驱动程序进行通讯。而Client和Service之间的进程间通讯是经过Binder驱动程序间接实现的。而Binder Manager是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。
1七、Handler的原理
Android中主线程是不能进行耗时操做的,子线程是不能进行更新UI的。因此就有了handler,它的做用就是实现线程之间的通讯。
handler整个流程中,主要有四个对象,handler,Message,MessageQueue,Looper。当应用建立的时候,就会在主线程中建立handler对象,
咱们经过要传送的消息保存到Message中,handler经过调用sendMessage方法将Message发送到MessageQueue中,Looper对象就会不断的调用loop()方法
不断的从MessageQueue中取出Message交给handler进行处理。从而实现线程之间的通讯。
1八、Binder机制原理
在Android系统的Binder机制中,是有Client,Service,ServiceManager,Binder驱动程序组成的,其中Client,service,Service Manager运行在用户空间,Binder驱动程序是运行在内核空间的。而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,Service Manager提供辅助管理的功能,而Client和Service正是在Binder驱动程序和Service Manager提供的基础设施上实现C/S 之间的通讯。其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互,Client、Service,Service Manager经过open和ioctl文件操做相应的方法与Binder驱动程序进行通讯。而Client和Service之间的进程间通讯是经过Binder驱动程序间接实现的。而Binder Manager是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。
1九、热修复的原理
咱们知道Java虚拟机 —— JVM 是加载类的class文件的,而Android虚拟机——Dalvik/ART VM 是加载类的dex文件,
而他们加载类的时候都须要ClassLoader,ClassLoader有一个子类BaseDexClassLoader,而BaseDexClassLoader下有一个数组——DexPathList,是用来存放dex文件,当BaseDexClassLoader经过调用findClass方法时,实际上就是遍历数组,
找到相应的dex文件,找到,则直接将它return。而热修复的解决方法就是将新的dex添加到该集合中,而且是在旧的dex的前面,
因此就会优先被取出来而且return返回。
固然除了这种方式外,还有Instant run等方案,请你们自行查找资料学习。
20、Android内存泄露及管理
(1)内存溢出(OOM)和内存泄露(对象没法被回收)的区别。
(2)引发内存泄露的缘由
(3) 内存泄露检测工具 ------>LeakCanary
内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;好比申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。内存溢出通俗的讲就是内存不够用。
内存泄露 memory leak:是指程序在申请内存后,没法释放已申请的内存空间,一次内存泄露危害能够忽略,但内存泄露堆积后果很严重,不管多少内存,早晚会被占光
内存泄露缘由:
1、Handler 引发的内存泄漏。
解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用,其生命周期就和外部类无关,
若是Handler里面须要context的话,能够经过弱引用方式引用外部类
2、单例模式引发的内存泄漏。
解决:Context是ApplicationContext,因为ApplicationContext的生命周期是和app一致的,不会致使内存泄漏
3、非静态内部类建立静态实例引发的内存泄漏。
解决:把内部类修改成静态的就能够避免内存泄漏了
4、非静态匿名内部类引发的内存泄漏。
解决:将匿名内部类设置为静态的。
5、注册/反注册未成对使用引发的内存泄漏。
注册广播接受器、EventBus等,记得解绑。
6、资源对象没有关闭引发的内存泄漏。
在这些资源不使用的时候,记得调用相应的相似close()、destroy()、recycler()、release()等方法释放。
7、集合对象没有及时清理引发的内存泄漏。
一般会把一些对象装入到集合中,当不使用的时候必定要记得及时清理集合,让相关对象再也不被引用。
2一、Fragment与Fragment、Activity通讯的方式
1.直接在一个Fragment中调用另一个Fragment中的方法
2.使用接口回调
3.使用广播
4.Fragment直接调用Activity中的public方法
2二、Android UI适配
字体使用sp,使用dp,多使用match_parent,wrap_content,weight
图片资源,不一样图片的的分辨率,放在相应的文件夹下可以使用百分比代替。
2三、app优化
app优化:(工具:Hierarchy Viewer 分析布局 工具:TraceView 测试分析耗时的),app优化主要从如下几个方面展开:
App启动优化
布局优化
响应优化
内存优化
电池使用优化
网络优化
App启动优化(针对冷启动)
App启动的方式有三种:
冷启动:App没有启动过或App进程被killed, 系统中不存在该App进程, 此时启动App即为冷启动。
热启动:热启动意味着你的App进程只是处于后台, 系统只是将其从后台带到前台, 展现给用户。
介于冷启动和热启动之间, 通常来讲在如下两种状况下发生:
(1)用户back退出了App, 而后又启动. App进程可能还在运行, 可是activity须要重建。
(2)用户退出App后, 系统可能因为内存缘由将App杀死, 进程和activity都须要重启, 可是能够在onCreate中将被动杀死锁保存的状态(saved instance state)恢复。
优化:
Application的onCreate(特别是第三方SDK初始化),首屏Activity的渲染都不要进行耗时操做,若是有,就能够放到子线程或者IntentService中
布局优化
尽可能不要过于复杂的嵌套。可使用,,
响应优化
Android系统每隔16ms会发出VSYNC信号重绘咱们的界面(Activity)。
页面卡顿的缘由:
(1)过于复杂的布局.
(2)UI线程的复杂运算
(3)频繁的GC,致使频繁GC有两个缘由:一、内存抖动, 即大量的对象被建立又在短期内立刻被释放.二、瞬间产生大量的对象会严重占用内存区域。
内存优化:参考内存泄露和内存溢出部分
电池使用优化(使用工具:Batterystats & bugreport)
(1)优化网络请求
(2)定位中使用GPS, 请记得及时关闭
网络优化(网络链接对用户的影响:流量,电量,用户等待)可在Android studio下方logcat旁边那个工具Network Monitor检测
API设计:App与Server之间的API设计要考虑网络请求的频次, 资源的状态等. 以便App能够以较少的请求来完成业务需求和界面的展现.
Gzip压缩:使用Gzip来压缩request和response, 减小传输数据量, 从而减小流量消耗.
图片的Size:能够在获取图片时告知服务器须要的图片的宽高, 以便服务器给出合适的图片, 避免浪费.
网络缓存:适当的缓存, 既可让咱们的应用看起来更快, 也能避免一些没必要要的流量消耗。
2四、图片优化
(1)对图片自己进行操做。尽可能不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource来设置一张大图,由于这些方法在完成decode后,
最终都是经过java层的createBitmap来完成的,须要消耗更多内存.
(2)图片进行缩放的比例,SDK中建议其值是2的指数值,值越大会致使图片不清晰。
(3)不用的图片记得调用图片的recycle()方法。
2五、HybridApp WebView和JS交互
Android与JS经过WebView互相调用方法,其实是:
Android去调用JS的代码
经过WebView的loadUrl(),使用该方法比较简洁,方便。可是效率比较低,获取返回值比较困难。
经过WebView的evaluateJavascript(),该方法效率高,可是4.4以上的版本才支持,4.4如下版本不支持。因此建议二者混合使用。
JS去调用Android的代码
漏洞产生缘由是:当JS拿到Android这个对象后,就能够调用这个Android对象中全部的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
解决方式:
(1)Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击。
(2)在Android 4.2版本以前采用拦截prompt()进行漏洞修复。
(1)Android经过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url
(2)解析该 url 的协议
(3)若是检测到是预先约定好的协议,就调用相应方法
这种方式的优势:不存在方式1的漏洞;缺点:JS获取Android方法的返回值复杂。
2六、Universal-ImageLoader,Picasso,Fresco,Glide对比
Fresco 是 Facebook 推出的开源图片缓存工具,主要特色包括:两个内存缓存加上 Native 缓存构成了三级缓存。
优势:
图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间缓冲数据也存放在本地堆内存, 因此, 应用程序有更多的内存使用, 不会由于图片加载而致使oom, 同时也减小垃圾回收器频繁调用回收 Bitmap 致使的界面卡顿, 性能更高。
渐进式加载 JPEG 图片, 支持图片从模糊到清晰加载。
图片能够以任意的中心点显示在 ImageView, 而不只仅是图片的中心。
JPEG 图片改变大小也是在 native 进行的, 不是在虚拟机的堆内存, 一样减小 OOM。
很好的支持 GIF 图片的显示。
缺点:
框架较大, 影响 Apk 体积
使用较繁琐
Universal-ImageLoader:(估计因为HttpClient被Google放弃,做者就放弃维护这个框架)
优势:
1.支持下载进度监听
2.能够在 View 滚动中暂停图片加载,经过 PauseOnScrollListener 接口能够在 View 滚动中暂停图片加载。
3.默认实现多种内存缓存算法 这几个图片缓存均可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。
4.支持本地缓存文件名规则定义
Picasso 优势
2.支持优先级处理。每次任务调度前会选择优先级高的任务,好比 App 页面中 Banner 的优先级高于 Icon 时就很适用。
3.支持延迟到图片尺寸计算完成加载
4.支持飞行模式、并发线程数根据网络类型而变。 手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数,好比 wifi 最大并发为 4,4g 为 3,3g 为 2。 这里 Picasso 根据网络类型来决定最大并发数,而不是 CPU 核数。
5.“无”本地缓存。无”本地缓存,不是说没有本地缓存,而是 Picasso 本身没有实现,交给了 Square 的另一个网络库 okhttp 去实现,这样的好处是能够经过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过时时间。
Glide 优势
不只仅能够进行图片缓存还能够缓存媒体文件。Glide 不只是一个图片缓存,它支持 Gif、WebP、缩略图。甚至是 Video,因此更该当作一个媒体缓存。
支持优先级处理。
与 Activity/Fragment 生命周期一致,支持 trimMemory。Glide 对每一个 context 都保持一个 RequestManager,经过 FragmentTransaction 保持与 Activity/Fragment 生命周期一致,而且有对应的 trimMemory 接口实现可供调用。
支持 okhttp、Volley。Glide 默认经过 UrlConnection 获取数据,能够配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。
内存友好。Glide 的内存缓存有个 active 的设计,从内存缓存中取数据时,不像通常的实现用 get,而是用 remove,再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,若是引用计数为空则回收掉。内存缓存更小图片,Glide 以 url、view_width、view_height、屏幕的分辨率等作为联合 key,将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小与 Activity/Fragment 生命周期一致,支持 trimMemory。图片默认使用默认 RGB_565 而不是 ARGB_888,虽然清晰度差些,但图片更小,也可配置到 ARGB_888。
6.Glide 能够经过 signature 或不使用本地缓存支持 url 过时.
2七、Xutils, OKhttp, Volley, Retrofit对比
Xutils这个框架很是全面,能够进行网络请求,能够进行图片加载处理,能够数据储存,还能够对view进行注解,使用这个框架很是方便,可是缺点也是很是明显的,使用这个项目,会致使项目对这个框架依赖很是的严重,一旦这个框架出现问题,那么对项目来讲影响很是大的。
OKhttp:Android开发中是能够直接使用现成的api进行网络请求的。就是使用HttpClient,HttpUrlConnection进行操做。okhttp针对Java和Android程序,封装的一个高性能的http请求库,支持同步,异步,并且okhttp又封装了线程池,封装了数据转换,封装了参数的使用,错误处理等。API使用起来更加的方便。可是咱们在项目中使用的时候仍然须要本身在作一层封装,这样才能使用的更加的顺手。
Volley:Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection, 甚至支持OkHttp,并且Volley里面也封装了ImageLoader,因此若是你愿意你甚至不须要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可使用,稍复杂点的需求仍是须要用到专门的图片加载框架。Volley也有缺陷,好比不支持post大数据,因此不适合上传文件。不过Volley设计的初衷自己也就是为频繁的、数据量小的网络请求而生。
Retrofit:Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架,RESTful是目前流行的一套api设计的风格, 并非标准。Retrofit的封装能够说是很强大,里面涉及到一堆的设计模式,能够经过注解直接配置请求,可使用不一样的http客户端,虽然默认是用http ,可使用不一样Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava + Dagger2 能够说是目前比较潮的一套框架,可是须要有比较高的门槛。
Volley VS OkHttp
Volley的优点在于封装的更好,而使用OkHttp你须要有足够的能力再进行一次封装。而OkHttp的优点在于性能更高,由于 OkHttp基于NIO和Okio ,因此性能上要比 Volley更快。IO 和 NIO这两个都是Java中的概念,若是我从硬盘读取数据,第一种方式就是程序一直等,数据读完后才能继续操做这种是最简单的也叫阻塞式IO,还有一种是你读你的,程序接着往下执行,等数据处理完你再来通知我,而后再处理回调。而第二种就是 NIO 的方式,非阻塞式, 因此NIO固然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基础上作的一个更简单、高效处理数据流的一个库。理论上若是Volley和OkHttp对比的话,更倾向于使用 Volley,由于Volley内部一样支持使用OkHttp,这点OkHttp的性能优点就没了, 并且 Volley 自己封装的也更易用,扩展性更好些。
OkHttp VS Retrofit
毫无疑问,Retrofit 默认是基于 OkHttp 而作的封装,这点来讲没有可比性,确定首选 Retrofit。
Volley VS Retrofit
这两个库都作了不错的封装,但Retrofit解耦的更完全,尤为Retrofit2.0出来,Jake对以前1.0设计不合理的地方作了大量重构, 职责更细分,并且Retrofit默认使用OkHttp,性能上也要比Volley占优点,再有若是你的项目若是采用了RxJava ,那更该使用 Retrofit 。因此这两个库相比,Retrofit更有优点,在能掌握两个框架的前提下该优先使用 Retrofit。可是Retrofit门槛要比Volley稍高些,要理解他的原理,各类用法,想完全搞明白仍是须要花些功夫的,若是你对它只知其一;不知其二,那仍是建议在商业项目使用Volley吧。
一、线程中sleep和wait的区别
(1)这两个方法来自不一样的类,sleep是来自Thread,wait是来自Object;
(2)sleep方法没有释放锁,而wait方法释放了锁。
(3)wait,notify,notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep能够在任何地方使用。
二、Thread中的start()和run()方法有什么区别
start()方法是用来启动新建立的线程,而start()内部调用了run()方法,这和直接调用run()方法是不同的,若是直接调用run()方法,则和普通的方法没有什么区别。
三、String,StringBuffer,StringBuilder区别
一、三者在执行速度上:StringBuilder > StringBuffer > String (因为String是常量,不可改变,拼接时会从新建立新的对象)。
二、StringBuffer是线程安全的,StringBuilder是线程不安全的。(因为StringBuffer有缓冲区).
四、Java中重载和重写的区别:
一、重载:一个类中能够有多个相同方法名的,可是参数类型和个数都不同。这是重载。
二、重写:子类继承父类,则子类能够经过实现父类中的方法,从而新的方法把父类旧的方法覆盖。
五、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服务器利用会话密钥加密与客户端之间的通讯。
六、TCP和UDP的区别
tcp是面向链接的,因为tcp链接须要三次握手,因此可以最低限度的下降风险,保证链接的可靠性。
udp 不是面向链接的,udp创建链接前不须要与对象创建链接,不管是发送仍是接收,都没有发送确认信号。因此说udp是不可靠的。
因为udp不须要进行确认链接,使得UDP的开销更小,传输速率更高,因此实时行更好。
七、Socket创建网络链接的步骤
创建Socket链接至少须要一对套接字,其中一个运行与客户端--ClientSocket,一个运行于服务端--ServiceSocket
一、服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待链接的状态,实时监控网络状态,等待客户端的链接请求。
二、客户端请求:指客户端的套接字提出链接请求,要链接的目标是服务器端的套接字。注意:客户端的套接字必须描述他要链接的服务器的套接字,
指出服务器套接字的地址和端口号,而后就像服务器端套接字提出链接请求。
三、链接确认:当服务器端套接字监听到客户端套接字的链接请求时,就响应客户端套接字的请求,创建一个新的线程,把服务器端套接字的描述
发给客户端,一旦客户端确认了此描述,双方就正式创建链接。而服务端套接字则继续处于监听状态,继续接收其余客户端套接字的链接请求。