temp.jpg
1:熟练使用Android常用性能调优
1:内存优化
GC释放对象包含(引用点):java栈中引用的对象;静态方法引用的对象;静态常量引用的对象;Native中JNI引用的对象,Thread。
内存溢出原因:瞬间申请了大量内存导致OOM;长期不能释放导致超过阈值导致OOM;小范围累积不能释放导致卡顿的OOM。
优化方式:利用profiler查看堆栈快照,具体查看波动内存是哪里导致的。
利用leakCanary工具查看生成的dump文件。
2:UI布局优化
UI卡顿的情况:View过渡绘制;Layout过于复杂,无法在16ms内完成渲染;View频繁出发measure,layout。
优化方式:开启GPU过渡绘制工具查看当前布局的绘制情况。
a:用RealtiveLayout代替LinearLayout
b:include,ViewStub,merge标签的使用
3:代码质量优化
a:使用as自带的unused resource清理无用资源
b:代码混淆
4:网络优化
a:用as自带的profiler进行网络监听。
ANR产生的原因:
Activity5s内无响应;广播10s无法处理完;服务service20s无法处理完。
网络请求中的图片可以用webp格式,质量相同的情况下减少流量。
优化方式:
一般多线程可以通过Asynctask处理,可以控制线程的顺序,执行完A后根据A返回的参数执行B线程。
5:耗电优化
a:需要进行网络请求时先判断当前的网络状态。
b:当有wifi和移动网络时候,优先选择wifi比移动网络耗电低。
c:减少后台任务的唤醒操作。
6:启动优化
a:冷启动,杀死进程后启动或程序第一次启动,耗时最久,因为要重新经历application初始化,启动ui线程,创建Activity,导入视图绘制视图等。
b:暖启动,当activity被销毁,但在内存中常驻时,启动减少了对象的初始化,布局加载等,启动时间短。
c:热启动,启动时间最短,比如按home键重新回到应用。
优化方式:Application创建过程尽量少,减少布局层次,启动页预加载等。
2:Java常用设计模式
单例模式:某个类只能有一个实例,提供一个全局的访问点。避免对象的重复创建,提高资源的有效利用。
代理模式:为其他对象提供一个代理,以便控制这个对象的访问。
工厂模式:定义一个创建对象的接口,让子类决定实例化哪个类。
观察者模式:对象间的一对多的依赖关系。
3:Android常用设计模式(架构)
MVC:model数据层,view视图层,controller业务逻辑控制层。
mvc通讯方式,有view通知controller,controller完成处理后重新赋值到model,然后model发送到view。
MVP:model数据层,view视图层,persenter。view与model不发生联系,通过persenter处理。优点:解耦,提高维护性。缺点:接口和类暴增;当业务逻辑到达一定量时候,Activity类会臃肿;一旦视图变更,persenter也要改动。
MVVM:viewmodel,伪fragment,跟随Activity的生命周期,data-bingding数据绑定,用retrofit2+rxjava可以直接将返回数据变成一个可观察对象,简化viewmodel。viewmodel不关心具体业务逻辑,只做数据处理响应操作。viewmodel不能持有上下文。
4:AndroidUI,网络,数据库框架
UI框架,基本上自定义或者使用原生控件,图形图表用MPAndroidChart
网络框架:okhttp,
a:okhttpclient实现了Call.Fctory,负责为Request创建Call;
b:RealCall为Call的具体实现,其enqueue()异步请求接口通过Dispatcher()调度器利用ExcutorService实现,而最终进行网络请求时和同步的execute()接口一致,都是通过getResponseWithinterceptorChain()函数实现
c:getResponseWithInterceptorChain()中利用Interceptor链条,责任链模式分层实现缓存、透明压缩、网络IO等功能;最终将响应数据返回给用户。
数据库框架:Room,Greendao。
属于轻量级orm框架(对象映射型数据库),配合sqlcipher支持加密。GreenDao支持protobuf协议,不需要映射就可以与服务器交互。
room可以做很好的迁移和升级,编译时检查,减少出错概率。
5:自定义控件
自定义View:继承View
基于现有组件:继承View的派生类
组合方式:自定义控件中包含了其他的组件
onMeasure:测量View的大小宽高
根据父View和MeasureSpec加上子view自己的LayoutParams,通过相应的转化规则而得到大小。
MeasureSpec代表宽度或高度的要求,每个MeasureSpec都包含了size和mode,MeasureSpec的模式主要分为:
(1)exactly:父容器已经测量出子view的大小,对应view的layoutparams的match_parent。
(2)at_most:父容器已经限制了view的大小,对应view的layoutParams的wrap_content。
onLayout:计算显示位置。
对View进行排版布局,要看父容器,也就是viewGroup。
onDraw:绘制背景,内容,绘制子view等
6:RecyclerView优缺点
RecyclerView卡顿情况:布局复杂,多层嵌套,设置setNestedScrollingEnable(false);含视频,滑动到item时加载,item滑出界面释放资源;含图片,图片懒加载(默认图占位)
RecyclerView4级缓存:
第一级mChangedScrap匹配position或者id获取holder缓存。
第二级从mAttachedScrap中通过匹配position获取holder缓存,或者通过childHelper找到隐藏但没有被移除的View,通过getChildViewHolderInt(view)方法获取holder缓存,或者从mCachedViews中通过匹配position获取holder缓存。
第三级从mAttachedScrap中通过匹配id获取holder缓存,或者从mCachedViews中通过匹配id获取holder缓存。
第四级从ViewChacheExtension获取holder缓存。
第五级通过RecyclerView的ViewHolder缓存池获取holder。
7:Http&Socket编程,TCP/IP原理
TCP:面向连接的,数据顺序,数据正确性,面向字节流。(类似打电话,需要三次握手,4次挥手)
UDP:面向无连接的,基于数据包的,可能丢包,数据顺序不保证(类似发短信)
三次握手:
A:你好我是A。
B:你好A,我是B。
A:你好B
四次挥手:
A:B啊,我不想玩了。
B:哦,你不想玩了,我知道了。(这个时候,只是A不想玩了,A不再发送数据,但B可能有未完成的数据,所以需要等待)
B:A啊,好吧,我也不玩了,拜拜。
A:好的,拜拜。
Http和Https区别:
https是具有安全性的ssl加密身份认证的传输协议,需要到ca申请证书。端口443。
http是超文本传输协议,信息是明文传输。端口是80,是无状态连接。
8:图片优化,Glide源码
bitmap占用内存=图片长*图片宽*一个像素点占用的字节数。
bitmap.config中argb_4444和argb_8888代表一个像素点占用多少位。
图片压缩方式:
a:质量压缩,bitmap.compress不会改变图片所在内存大小,改变的是图片所占磁盘大小。
b:设置图片格式,png无损,jpeg有损,webp有损和无损,体积更小。
c:采样率压缩inSampleSize宽高压缩。
d:缩放压缩,减少图片的像素来降低磁盘和内存大小,可用于缩略图。
e:JNI调用JPEG库。(图片引擎采用skia,去掉了压缩算法导致)
Glide:
用法是with().load().into()。用法和pissco一致,是pissco的升级版。
SupportRequestManagerFragment是一致存在于栈中的fragment。不管上下文是用activity还是application的基本不会造成OOM,LruCache通过键值对形式存储bitmap,通过linkedHashmap保证插入顺序,Gilde可以从LruCache获取图片,从弱引用中获取缓存,从网络请求中获取图片。
9:flutter原理优势,weex对比
weex和flutter都是write once,run everywhere。
weex主要分为JS Bridge、Render、Dom。
JsBridge主要用来和js端实现进行双向通信;Dom主要用于负责dom解析,映射,添加等操作,最后通知UI线程更新。Render负责在UI线程中对dom实现渲染。不支持热重载,不能真机调试,支持热更新。适合单页面快速开发。
Flutter,基于Dart语言,基于独有的图形引擎Skia,不需要要桥接,不基于webkit,解决比较彻底。
摒弃JSBridge,Flutter是直接编译成本地代码,用skia渲染展示。热重载hot reload,jsBridge需要build打包。flutter不支持热更新,适合整体app开发。
10:Handle机制(postDelay),postDelay执行时候是什么时候把message添加Queue中的?怎么保证next时候message的唯一性?
handler不仅仅能将子线程的数据发送给主线程,它试用与任意两个线程间的通信方式。
在App初始化时候ActivityThread的main方法实现了looper的prepare和loop方法,所有在主线程使用handler时候不需要looper.prepare。
1:在使用handler时候,handler所创建的线程需要维护一个唯一的Looper对象,每个线程对应一个Looper,每个线程的Looper通过ThreadLocal来保证。Looper对象内部又维护有唯一一个MessageQueue,所以一个线程可以有多个handler,但是只有有一个Looper和一个MessageQueue。
2:在Message在MessageQueue中不是通过一个列表来存储的,而是将Message存入到上一个Message的next中,取出时候通过顶部的Message就能按放入的顺序依次取出Message。
3:Looper对象通过loop方法开启一个死循环,不断从Loop的MessageQueue中取出message,然后通过handler将消息传回handler所在的线程。
handler内存泄漏原因:
当其他线程持有了该handler,线程没有被销毁,则Activity一直被Handler持有导致无法回收。
解决方式:
使用静态内部类+弱引用方式。
psotDelay(new Runnable())运行在主线程中,因为runnable会在handler所依附的线程中执行,handler是主线程创建,所以自然依附在主线程中。
为什么loop死循环不会卡死:
线程是一段可执行的代码,当执行完后线程的生命周期便终止,线程退出。而主线程我们希望一直运行下去,死循环便能保证不会被退出。真正导致卡死主线程的操作是在回调onCreate/onStart/onResume等操作时间过长导致ANR,looper.loop本身不会导致应用卡死。
handler.postDelay并不是先等待一定的时间再放入到MessageQueue中,而是直接进入MessageQueue,以MessageQueue的时间顺序排列和唤醒的方式结合实现的。使用后者的方式,我认为是集中式的统一管理了所有message,而如果像前者的话,有多少个delay message,则需要起多少个定时器。前者由于有了排序,而且保存的每个message的执行时间,因此只需一个定时器按顺序next即可
11:触摸事件机制?onTouchEvent&onClick&setOnClickLisenter执行顺序?移动过程中move,只需要前5s做拦截后不拦截怎么处理?
Activity/View处理触摸事件的方法:
dispatchTouchEvent()
onTouchEvent()
ViewGroup触摸事件处理:
dispatchTouchEvent()
onInterceptTouchEvent()
onTouchEvent()
在activity中当用户屏幕点击了后会先触发dispatchTouchEvent()如果view处理该事件则返回true,事件传递结束。如果返回false则调用onTouchEvent()处理该事件。
在ViewGroup中ViewGroup的dispatchTouchEvent先判断ViewGroup是否拦截Touch事件,如果拦截了则不向下传递直接调用TouchEvent处理事件,如果没有拦截则遍历所有子view找到点击的那个View把touch事件传递给它。viewgroup的onInterceptTouchEvent方法默认false,viewgroup事件分发都会调用它,一旦onInterceptTouchEvent返回true则表示拦截了事件,后续进行事件分发不再调用onInterceptTouchEvent方法。
总体优先级 setTouchListener > onTouchEvent > onClick > setClickListener
注意:DOWN或UP就是一个事件,不是DOWM+MOVE+UP才是一个事件,加起来是我们称作一系列事件
重写onTouchEvent时千万别删了super.onTouchEvent(event)——本人手贱,为此付出过惨痛代价。
待补充!!!!
---------------------
12:如何计算View大小&如何对子控件进行布局
计算View大小:
view在测量过程和activity生命周期不是同步的,所以在onCreate/onStart/onResume获取view宽高是0。
在onWindowFocusChanged里面获取。(getMeasuredWidth(),getMesureHeight())
子View布局:
可以通过addView方式,infalte布局
13:Binder机制
进程间通信方案。
优点:
1:性能方面,为了省电,Binder相对于传统的Socket方式更加高效,sokect,消息队列都需要2次,共享内存方式一次内存拷贝都不需要,但是实现方式比较复杂。
2:安全方面,socket通信ip地址容易进行伪造,binder机制支持通信双方做身份校验。
binder通信4种角色:
Clinet进程:使用服务的进程;Servie进程:提供服务的进程;ServiceManager进程;Binder驱动:负责建立Binder通信。
Binder和aidl区别:
1:他们都是远程调用有关。
2:Binder是一个对象,继承IBinder对象,AIDL是android提供的接口定义语言。
3:作用范围不同,如果在一个应用里实现远程调用使用Binder即可,如果是在多应用之间远程通信,则用aidl。
14:LMK机制
LMK:low memory killer
内存不足时调用oom,LMK每隔一段时间会检查。
(1)当系统发现内存不足时候,会执行low memory killer杀进程,并回收内存。
(2)当app请求一块新的内存空间但发现没有足够空间时候,会执行low memory killer杀进程,收回内存后在进行内存分配。
15:日志记录框架(美团logan)
logan优点:
1:采用先压缩后加密的顺序,使用流式加密和压缩,减少cpu使用。
2:使用AES进行日志加密(对称加密,像RES是非对称加密)确保日志安全。
3:核心逻辑在c层完成,提供跨平台能力,内存不会在java堆中占用,提高了性能。
16:EventBus原理
register注册,post发送消息。
EventBus解耦其实是使用了反射,在register时候会通过反射将信息记录下来。
观察者模式:通过subscrible订阅消息,Observer观察者。
源码解析:
getDefalut()是一个单例方法,保证当前只有一个EventBus实例。
17:AAC框架原理
AAC:处理UI周期与数据的持久化。
AAC应用:liveData和viewModel
liveData需要用到LifeCyclerOwner,可以监听生命周期。
ViewModel用于存储和管理UI变化的相关数据,横竖屏后仍然可以保存数据,并且不能持有context。
18:插件化
问题:
模块间耦合度过大沟通成本高,app方法数超过65535等问题
解决:
将一个apk拆分成多个小apk,每个小apk能单独运行。业务模块基本完全解耦。
1:dex加载原理
dexClassLoader:可以加载文件系统上的jar、dex、apk。
PathClassLoader:可以加载/data/app目录下的apk,只能加载已安装的apk。
2:Android资源加载与管理
AssetManager、resoures是资源加载与管理的核心类,通过反射调用AssetManager的addAssetPath把插件中的资源加载进来。
3:四大组件的加载与管理(怎么注册activity?)
Activity通过proxyActivity进行代理;
通过Hook系统服务Activity Manager Service绕过清单文件的注册。
19:热修复
image
腾讯的tinker和阿里的andfix。
本地热修复
1:修改好代码后编译后生成.class文件
2:用sdk中提供的dx工具将需要替换的.class文件转化成dex。
3:将.dex文件放入磁盘,创建一个DexClassLoader,通过PathClassLoader遍历出需要修改的dexElements,设值新的参数。
4:启动时候重新loadFixdex()
20:组件化
目的:提高代码的复用性。
使用场景:
1:业务,需要做一个实时上传位置的功能。
2:基础lib,百度地图,高德地图。
3:应用,美团外卖上传位置,美团酒店上传位置。
21:Activity启动过程
1:通过Launcher启动Activity或者startActivity来启动,都是通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;
2:ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动activity的相关信息;
3:ActivityStack通知Application Thread要进行Activity启动调度了。
4:Application Thread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;
5:如果是通过Launcher的情况,ActivityManagerService会调用startProcessLocked来创建新的进程,对于startActivity来启动的情况,这一步不需要执行,直接在原来Activity所在的进程中启动。
6:ActivityManagerService调用Application Thread.scheduleLaunchActivity接口,通知相信的进程启动Activity;
7:Application Thread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后启动起来了。
22:AMS,PMS源码
都是属于framework层
AMS:ActivityManagerService,android内核的核心功能之一,系统在启动SystemService时启动此服务。
PMS:PackageManagerService
WMS:WindowManagerService
24:hashmap原理与Hashtable区别,arrayList,LinkedList原理比较
HashMap是非线程安全的,只试用单线程环境下,实现了Serializable接口,支持序列化,内部维护了一个存储数据的Entry数组,key和value都允许为null。
HashTable继承Dictionary类,key和value不允许出现null值。
25:单例设计模式的双重校验的目的?去掉第一个判空或第二个判空有啥不同?
synchronized锁住的是代码段,volatile关键字可以防止jvm对这个变量进行优化,双重校验目的:因为可能会有多个线程一起进入同步块外的if,如果在同步块内不进行二次校验的话就会生成多个实例。
26:工厂模式解决了什么问题?
工厂模式:把对象的创建放在一个工厂类中,通过参数来创建不同的对象。在新增对象类型的时候,只需要改变工厂方法,减少维护量。
27:retrofit,rxjava原理,okhttp用到了哪些设计模式,连接池的实现原理,rxjava线程切换的原理。
retrofit:
通过动态代理生成实现类,使用注解+java接口来定义API接口,Retrofit,create()创建接口动态代理,为接口的每个method创建一个对应的ServiceMethod,并使用这个ServiceMethod对象创建OkhttpCall,并使用ServiceMethod实例的callAdater来调用okhttpCall并返回结果。
Rxjava原理:
是一种基于观察者模式的响应式编程框架。Rxjava中线程切换时候可以用subscribeOn(Schedulers.io())或subscribeOn(AndroidSchedulers.mainThread())。线程切换是执行在订阅回调层。
rxjava线程切换原理:
待补充。。。
线程池原理:
先启动若干数量的线程,并让这些线程处理睡眠状态,当客户端有一个新请求时就会唤醒某一个睡眠线程,让它来处理这个请求,当处理完这个请求,线程又休眠。创建线程池为了统一管理,提高性能。
28:jvm模型,java内存模型,垃圾回收机制,垃圾回收哪个区域,对象在内存哪个区域。
jvm内存模型:方法区,堆,程序计数器,本地方法栈。
垃圾回收机制执行:
1:年老代被写满
2:持久带被写满
3:System.gc()被显示调用
4:上一次gc之后heap的分配策略动态变化。
对象在内存中的堆里面。JVM所有对象都是在堆中分配内存空间,栈只是保存局部变量和临时变量,如果是对象只保存引用。
29:startService和bindService区别,多次启动调用哪些方法?
1:生命周期上的区别:
startService:onCreate-->onStartCommand-->onStop-->onDestory
bindService:onCreate-->onBind-->unBindService-->onDestroy。
多次调用startService时service只能被创建一次,每次调用startService,onStartCommand都会执行;
第一次执行bindService时,onCreate-->onBind都会被调用,多次执行时候,onCreate-->onBind不会多次调用。
30:Activity旋转会调用哪些方法?
没有任何配置的情况下:
onPause()--onStop()--onDestroy()--onCreate()--onStart()--onResume();
31:冒泡排序&手写单例
冒泡:
public static void main(String){
int arry[]={2,3,1,4};
for(int i=0;i<arry.length-1;i++){
for(int j=0;j<arry.length-i-1;j++){
if(arry[j]>arry[j+1]){
int temp=arry[j];
arry[j]=arry[j+1];
arry[j+1]=temp;
}
}
}
for(int num:array){
syso.print(num);
}
}
单例:
public class SingleIntence{
private static volatile SingleIntence intence;
public static SingleIntence(){
if(intence==null){
synczoid(SingleIntence.class){
if(intence==null){
intence=new SingleIntence();
}
}
}
return intence;
}
}
34:java中重载和多态
重载:
是内部的方法结构上的不同,同一个Method参数不同,实现同一类型的功能。
多态:
1:继承 2:重写(重写父类继承的方法)3:父类引用指向子类对象
35:java中注解
Annotation。
在构建过程中生成代码,注解不会出现在编译后的代码中,可以通过反射访问到这些注解。
一个简单的java注解@Entity,其中@就是告诉编译器是注解,Entiry是注解名,类似@Ovrrived。
37:屏幕适配方案
传统方案:
在res下建不同的values文件夹,创建不同的dimens。
今日头条:
通过反射适配系统的density(密度)值
密度=屏幕中1dp所占的多少像素点
限定符适配:
smallestwidth,通过宽高限定符,配置在manifast.xml中,程序启动时候读取xml设值。
38:跨进程通信方式(IPC),AIDL原理
Content Provider
广播
Aidl:
aidl其实就是通过Binder实现的,在定义好aidl文件后,as会生成相关的binder类,aidl并不是必须的文件,因为binder类可以手写出来。
message,bundle,contentProvider都是通过binder来实现的,只是他们的封装方式不一样。
Binder
Intent
41:Android动画
逐帧动画(放电影,一帧一帧)
补间动画(控制平移,旋转,缩放等)
属性动画(升级版的补间动画,支持任意属性的变化)
SurfaceView实现动画。
42:多线程同步问题,锁lock,syc
synchronized:可以加载代码快,对象中。是托管给jvm执行的
lock:需要指定起始位置和终止位置。是java写的控制锁的代码。
43:线程池ThreadPool
1:线程池管理器(ThreadPool)
用于创建并管理线程池,包括创建线程池,启动等
2:工作线程(PoolWorker)
线程池中线程,在没有任务时处理等待,可循环执行任务。
3:任务接口(Task)
每个任务必须实现的接口,供工作线程调度任务的执行。规定了任务的入口,收尾,执行状态等。
4:任务队列(TaskQueue)
用于存放没有处理的任务,提供一种缓冲机制。
44:android APT
Butterknife也是用apt方式。
通过注解方式编译时生成代码
45:APK安装过程
复制APK安装包到/data/app目录下,
解压并扫描安装包,
向资源管理器注入APK资源,
解析manifest文件,
在data/data目录下创建应用数据目录,
针对dalvik环境优化dex文件,
保存到dalvik-cache目录,
将manifest文件解析出的组件权限注册到packgeManagerService并发送广播。
46:invalidate()和postInvalidate()区别
invalidate会刷新整个View,只能在UI线程中调用。
postInvalidate,可以在非UI线程中去调用刷新UI,postInvalidate是通过handler将刷新事件通知到handlerMessage中执行invalidate的。
47:Parcelable和Serializable区别
Parcelable:
Android提供的,代码多,速度高
Serializable:
java自带的,代码量少,速度低
49:匿名共享内存,使用场景
是什么?
在Android中,主要提供了MemoryFile这个类来供应用使用匿名共享内存,在android应用程序框架层,提供了一个MemoryFile接口来封装匿名共享内存文件的创建和使用,通过JNI调用底层c++方法。
使用场景:
使用Binder在进程间传递数据的时候,有时会报出TransactionTooLargeException这个异常,因为Binder驱动对内存的限制引起的,Binder通常传递数据限制为1M。
50:ContentProvider实现原理,如何进行批量操作?
ContentProvider可以作为数据访问接口之外,还可以在不同应用程序之间进行数据共享。因为Binder传递数据有大小限制,所以用ContentProvider来处理比较高效。
ContentProvider必须在Manifest中声明。访问provider需要知道它的URI,所以把provider的URI作为公共常量出来。
ContentProviderOperation:
可以批量更新,插入,删除数据。
ContentProviderOperation.Builder:
newInsert 插入操作
newUpdate 更新操作
newDelete 删除操作
newAssertQuery 查询没有符合条件的数据
51:广播注册后不注销有什么问题?(内存泄漏)
广播在onReceiver方法中的参数Context,所以BroadCastReveiver中持有Activity,
而且广播不仅被Activity持有,可能还被ActivityManagerService等系统服务持有。
当Activity调用onDestroy方法时候,Activity并不能被回收,从而导致内存泄漏。
所以需要结束时候调用unregisterReceiver()。
53:BrocastReceive里面可不可以执行耗时操作?
onReceive()在10s内没有执行完会ANR。
55:Dalvik与ART区别?
Dalvik是Android虚拟机。dex格式是专为Dalvik提供的压缩格式。
Dalvik与JVM(java虚拟机)区别:
Dalvik基于寄存器,jvm基于java字节码。
Dalvik运行dex文件,jvm运行java字节码。
Dalvik比jvm占用空间更好,编译速度更快。
ART:
Android RunTime,在第一次安装时候,字节码会预编译成机器码,首次执行和启动速度更快。而Dalvik每次运行都会将字节码转换成机器码。
ART优点:
性能提升,电池续航能力更长,应用运行更流畅。
缺点:
机器码占用存储空间更大,字节码变成机器码后,可能增加包的大小。应用安装时间变长。
56:Android动态权限?各版本差异性?
5.0
沉浸式状态栏
6.0
动态权限,httpclient删除。
7.0 8.0 9.0
更注重耗电和后台优化。将bitmap中的像素点放在native层等。
57:ViewPager如何判断左右滑动?
监听addOnPageChangeListener(),当屏幕触摸时候先调用onPageScrolled,position等于Viewpager当前下标,向左滑=当前position,向右滑=position-1。
59:Asset目录与res目录的区别
Asset:文件路径+文件名,能获取子目录下的资源。
res: R.XX,不能获取子目录下的资源。
60:Application在多进程下多次调用onCreate()吗?
当manifest中配置了service,应用启动时候可能多次调用onCreate()。
解决办法:
在oncreate中获取进程名称,在不同的进程中进行不同的初始化即可。
61:FragmentPageAdater和FragmentStateAdapter区别?
FragmentPageAdater:fragment对象会一直在内存中,适用于少数的page情况。
FargmentStateAdapter:默认保存三个fragment,上一个当前的和下一个,一起对象的fragment会被销毁,但是在执行ondestroy时先调用onSaveInstenceState()来保存Fragment的状态,当fragment执行oncreate时候再把Bundle中的值取出来,比较适合多页面。
62:SurfaceView和View
SurfaceView的绘制方式效率非常高,继承自View,但是SurfaceView不需要重绘应用程序的窗口。
View通过刷新来重绘视图:
普通视图(子元素,局部刷新)的重绘都是会导致整个视图结构重绘一次。
63:AsyncTask异步任务
更新UI操作必须在主线程进行,下载图片,文件,网络请求需要在子线程进行,可以用handler机制。
Asynctask:
对线程和Handler进行了封装,可以直接对UI进行更新操作。
1:onPreExecute():执行在后台下载操作之前,与现行在主线程中。
2:doInBackground:核心方法,运行在子线程中
3:onPostExecute():后台下载完成后回调,运行在主线程中。
4:onProgressUpdate():在下载操作中调用publicProgress用于更新下载进度,运行在主线程中。
64:Servie&IntentService
Servie不能做耗时操作
IntentService继承自service,可以做后台下载等耗时操作。
65:Android强软弱虚引用的应用场景
1:强引用,定义的常量属于强引用,内存不足OOM时候也不会去回收该对象。
2:软引用,内存足够就不回收,不足是进行回收
3:弱引用,比软引用生命周期更短,只要被垃圾回收器线程发现,就会被回收。
4:虚引用,任何时候都可能会回收。
66:混淆的优点和使用场景(注解类)
nimifyEnabled true开启混淆
优点:
1:增加对apk反编译的困难性
2:减少apk体积
注意:
1:避免混淆Android基本组件,避免混淆get/set方法,避免混淆枚举类,序列化类等。
67:保证service不被杀死
在应用程序结束时候启动一个1像素的activity。
68:加速启动Activity
1:减少主线程的阻塞时间
2:提高Adater的效率
3:优化布局文件
4:使用profiler观察Activity内存网络情况。
70:equals与==区别
equals:比较的是两个对象是否相等
==:比较的是栈内存中的值
71 : try catch fianlly ,try里有return,finally还执行吗?
try里面有return也会执行finally,如果try里面报错会执行catch,最终还是执行finally。
72 : String,StringBuffer,StringBuilder区别
StringBuffer:
解决拼接字符串问题,append和add方法,属于线程安全。
StringBuilder:
在单线程操作字符串情况下使用StringBuilder。线程不安全。
String:
不经常发生变化的场景使用String。
74:方法锁,对象锁和类锁的意义和区别
方法锁:
当方法被synchronized修饰后,该方法一旦执行就会占用该锁,其他方法调用该方法时候被阻塞,直到这个锁被释放。
对象锁:
方法锁也叫对象锁,方法锁针对一个方法,对象锁针对一个代码快。
类锁:
synchronized修饰的静态方法,该类实例化对象共用一把锁,概念上的东西,不存在的。
75:java反射
反射:
对于任意一个类,都能得到它的属性和方法。通过setAccessible(true),可以得到私有属性
76:android安全性,防止抓包(公钥,指纹码),sslFactory,res非对称加密
安全性,可以通过混淆代码形式。
防止抓包,可以通过指纹码或者公钥证书,配合okhttp里面的sslFactory做防止中间人攻击。
res:服务端提供公钥,根据公钥对密码进行加密后传递给后台(每次值不一样,非对称加密),后台根据私钥解密出信息。
78:加壳原理(爱加密)
20190506114334.png
79:fragmentation框架(好用的第三方框架推荐)
单Activity+多Fragment设计。
1:方便查看栈信息。
2:支持懒加载
3:支持滑动退出fragment
4:继承supprotActivity
80:IO操作(断点续传原理)
RandomAccessFile:
支持对随即访问文件的读写。
81:androidX和support-v7
v4:
包含了基本的Fragment,ViewPager等
v7:
包含了v4的全部内容,新的控件和新的动画等。
v13:
针对平板。
androidX:
support库越来越臃肿,不便于维护,代码体积过大。as可以自带切换androidX。
84:wait() 和 sleep() 的区别?
wait:线程睡眠时,释放对象锁,其他线程可以访问。
sleep:线程睡眠时,仍然占有该锁,其他线程无法访问。
85:滑动不流畅怎么处理?50fps 有什么办法可以提高到 60fps?
60fps是每秒屏幕更新60次。
开启手机配置强制cpu加速
86:int、Integer有什么区别?
Integer是int的包装类,默认是null;int是基本数据类型,默认值是0;
87:android四种启动模式
1:standard标准模式:
每次启动都会重新创建一个新的实例入栈,不管之前是否存在。
2:SingleTop:
栈顶复用模式,如果Activity处于栈顶,则不再创建新的activity,如果不存在栈顶则重新创建实例。
3:SingleTask:
栈内复用模式,当需要创建这个activity时,如果activity已经存在则将所有的在它之上的activity销毁,让它处于栈顶。
4:singleInstance:
单实例模式,具有此模式的Activity单独位于一个任务栈中。只能有一个实例。
88:SharedPrefrence原理,能否夸进程,如何实现?
SharedPrefrence是基于xml实现的一种数据持久化手段。
SharedPrefrence不支持多进程。
SharedPrefrence的commit与apply一个是同步一个是异步。
SharedPrefrence不要存储过大数据。
89:消息推送原理,如何实现心跳连接?
1:轮询,tcp三次握手,4次挥手,比较耗电耗时。
2:心跳包,单次心跳不需要拆除tcp连接。
AlarmManager:全局定时闹钟,定时执行任务,cpu可以正常的休眠,执行任务时才唤醒cpu。
通过消息循环
90:敏捷开发scrum与传统开发
敏捷开发(结果不确定性):
1:响应计划高于遵循计划,随时可变优先级。
2:每日站会,需求评审会,迭代计划会,迭代回顾会。
3:需求通过故事点拆分,业务尽量不能交叉
4:燃尽图
瀑布模式:
需求->架构->编码->测试。不可回滚,可控性强。
91:是否看过Android源码
Logcat:
1:位于system/cor/logcat目录下
92:如何优化多个网络请求过慢导致界面长时间等待的情况
采用分模块加载,区域性loadng方式,提高交互体验。
93:webView加载h5的优化,webView内存泄漏是否了解。
页面加载速度优化:
1:选择合适的浏览器缓存机制
2:常用资源预加载,常用JS本地化及延迟加载,放在本地加载。
导致内存泄漏:
系统在attachTowindow和detachFromWindow处进行注册和反注册component callback导致。
封装自己的webView,不再xml中声明,在代码中直接new WebView,传入Application的上下文防止acitivty被滥用。
WebView webView = new WebView(getContext().getApplicationContext());
webFrameLayout.addView(webView, 0);
95:A启动B时activity的两个activity生命周期的流程。
A启动:
Aactivity oncreate onstart onResume
A进入B:
Activity onPause BActivity oncrete onstart onResume Activity onStop
B返回:
Bctivity onPause Activity restart start onResume Bactivity onStop ondestroy
A返回:
Activity onPase onstop ondestroy
96:如何监听activity是否后台切换到前台?不是在onReusme()中处理。
1:ActivityManager中处理:
getRunningTasks返回一个list集合,通过getClassName获取在前台的Activity。
2:OnResume中和onPause中记录一个变量。
98:两个进程如何使用binder进行双向通信?
aidl
99:如何监测普通对象是否泄漏,leakcanary在dump时卡顿厉害,这里如何优化?
增加debug和relase时候的不同依赖。在relase时候不进行监测。
100:对app架构的理解
1:可靠性
2:安全性
3:可扩展性
4:可定制行
5:可维护性
6:用户体验
。。。
101:PathClassLoader和DexClassLoader区别
PathClassLoader和DexClassLoader都是Android提供给我们的ClassLoader,都能加载dex
网上很多文章都说PathClassLoader只能加载已经被系统安装过的apk,DexClassLoader无此限制,然而我自己测试是都可以
根据art源码来看,两者都继承自BaseDexClassLoader,最终都会创建一个DexFile,不同点是一个关键的参数:optimizedDirectory,PathClassLoader为null,DexClassLoader则使用传递进来的
然后会根据optimizedDirectory判断对应的oat文件是否已经生成(null则使用/data/dalvik-cache/),如果有且该oat对应的dex正确则直接加载,否则触发dex2oat(就是这家伙耗了我们宝贵的时间!!),成功则用生成的oat,失败则走解释执行
ps:貌似Q版做了优化,不会再卡死在dex2oat里了
根据加载外部dex的实验,DexClassLoader会触发dex2oat,而PathClassLoader不会
102:ContentProvider
使用ContentResolver来获取ContentProvider提供的数据,同时注册ContentObserver监听Uri数据的变化
103:乐观锁和悲观锁
锁是为了避免自己在修改资源的时候,别人同时在修改,导致同一时间产生两份修改,不知道如何处理的情况而设置的独占资源,避免多个操作同时处理同一资源的技术。
乐观锁:默认为,某个线程在自己处理共享资源的时候,不会出现同一时刻来修改此资源的前提,只在处理完毕,最后写入内存的时候,检测是否此资源在之前未被修改。类似于读写锁的读锁就是乐观锁。
悲观锁:默认为,某个线程在自己处理共享资源的时候,一定会出现同一时刻来修改此资源,所以刚拿到这个资源就直接加锁,不让其他线程来操作,加锁在逻辑处理之前。类似,synchronized关键字,条件锁,数据库的行锁,表锁等就是悲观锁。
104:AIDL
1、定义 AIDL 是 android Interface Dialog Launguage , 是一个android 接口 对话语言,
2、作用是 为了实现进程间之间服务的通信。
3、实现方式, Service Client 和 Service Service 同时 持有一个 AIDL文件,编译的时候, 会自动变成一个可以引用的Binder子类。 Client 绑定服务成功后, 获取这个子类,可以使用里面的方法。 Service 在 onBind 方法里面 返回 这个Binder 类。
4、内部实现原理 是Binder ,实现了进程之间的通信。
105:线程池
线程池是用来存放线程的池子,里面的线程可以被重复利用,不浪费。
创建线程池:用Executors 。
singleThreadPool单一线程
fixedThreadPool固定数量的线程池
scheduleThreadPool周期任务
cacheThreadPool想建几个就建几个
网友评论