1、Android数据存储五种方式
查看:https://blog.csdn.net/liyue199512/article/details/52044360
查看:https://www.cnblogs.com/ITtangtang/p/3920916.html
(1)SharedPreference,存放较少的五种类型的数据,只能在同一个包内使用,生成XML的格式存放在设备中
(2) SQLite数据库,存放各种数据,是一个轻量级的嵌入式数据库
(3) File文件,通过读取写入方式生成文件存放数据
(4) ContentProvider,主要用于让其他应用程序使用保存的数据
(5)通过网络获取数据和写入数据到网络存储空间
2、Handler消息机制
-
Handler的基本原理
-
Handler是如何做到不阻塞主线程的
-
Handler是如何发送延迟消息的、如何在队列中调度消息(保证消息的先后顺序)
-
消息队列为空时,Handler是如何阻塞线程的
-
Handler阻塞时候,新消息到来是如何唤醒的
-
Handler是如何向其他线程发送消息的(handler的线程切换机制)
查看:https://blog.csdn.net/lmj623565791/article/details/38377229
查看handler源码:https://blog.csdn.net/iispring/article/details/47180325
查看:https://blog.csdn.net/qq_30379689/article/details/53394061
https://blog.csdn.net/yus201120/article/details/82015980
Handler消息机制包含Message、Handler、MessageQueen、Looper。
首先,是这个MessageQueen,MessageQueen是一个消息队列,它可以存储Handler发送过来的消息,其内部提供了进队和出队的方法来管理这个消息队列,其出队和进队的原理是采用单链表的数据结构(先进先出)进行插入和删除的,即enqueueMessage()方法和next()方法。这里提到的Message,其实就是一个Bean对象,里面的属性用来记录Message的各种信息。
然后,是这个Looper,Looper是一个循环器,它可以循环的取出MessageQueen中的Message,其内部提供了Looper的初始化和循环出去Message的方法,即prepare()方法和loop()方法。在prepare()方法中,Looper会关联一个MessageQueen,而且将Looper存进一个ThreadLocal中,在loop()方法中,通过ThreadLocal取出Looper,使用MessageQueen的next()方法取出Message后,判断Message是否为空,如果是则Looper阻塞,如果不是,则通过dispatchMessage()方法分发该Message到Handler中,而Handler执行handlerMessage()方法,由于handlerMessage()方法是个空方法,这也是为什么需要在Handler中重写handlerMessage()方法的原因。这里要注意的是Looper只能在一个线程中只能存在一个。这里提到的ThreadLocal,其实就是一个对象,用来在不同线程中存放对应线程的Looper。
最后,是这个Handler,Handler是Looper和MessageQueen的桥梁,Handler内部提供了发送Message的一系列方法,最终会通过MessageQueen的enqueueMessage()方法将Message存进MessageQueen中。我们平时可以直接在主线程中使用Handler,那是因为在应用程序启动时,在入口的main方法中已经默认为我们创建好了Looper。
3、Android中的动画以及自定义动画
查看:https://blog.csdn.net/ClAndEllen/article/details/79411999
1.Android动画的分类
1.1 补间动画
a.渐变动画支持四种类型:平移(Translate)、旋转(Rotate)、缩放(Scale)、不透明度
b. 只是显示的位置变动,View的实际位置未改变,表现为View移动到其他地方,点击事件仍在原处才能响应。
c. 组合使用步骤较复杂。
d. View Animation 也是指此动画。
1.2 帧动画
a. 用于生成连续的Gif效果图。
b. DrawableAnimation也是指此动画
1.3 属性动画
a.支持对所有View能更新的属性的动画(需要属性的setXxx()和getXxx())。
b. 更改的是View实际的属性,所以不会影响其在动画执行后所在位置的正常使用。
c. Android3.0(API11)及以后出现的功能,3.0之前的版本可使用github第三方开源库nineoldandroids.jar进行支持。
2.补间动画,帧动画,属性动画优缺点
2.1 补间动画优缺点
缺点:当平移动画执行完停在最后的位置,结果焦点还在原来的位置(控件的属性没有真的被改变)
优点:相对于逐帧动画来说,补间动画更为连贯自然
2.2 帧动画优缺点
缺点:效果单一,逐帧播放需要很多图片,占用控件较大
优点:制作简单
2.3 属性动画优缺点
缺点:(3.0+API出现)向下兼容问题。
优点:易定制,效果强。
4、Android中的事件分发机制
-
基本原理
-
一个事件的完成分发流程
-
如何拦截和消费一个事件
-
什么是事件队列
-
滑动冲突怎么解决
-
View滑动冲突分为两种:外层和内层滑动方向不一致,外层和内层滑动方向一致。解决方案分为两种,外部处理和内部处理。
外部拦截法:指点击事件都先经过父容器的拦截处理,父容器需要此事件,就拦截,外部拦截法需要重写父容器的onInterceptTouchEvent方法进行拦截
内部拦截法:内部拦截法指父容器不拦截任何事件,所有事件都传递到子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器进行处理,内部拦截法需要重写子元素的dispatchTouchEvent方法,配合requestDisallowInterceptTouchEvent方法进行使用。
-
查看:https://blog.csdn.net/carson_ho/article/details/54136311
查看:https://www.jianshu.com/p/e99b5e8bd67b
查看:https://blog.csdn.net/pgg_cold/article/details/79472193
当用户点击了屏幕,首先Activity先监测到,事件先传递到Activity中,Activity通过它的dispatchTouchEvent将事件分发到phoneWindow,phonewindow则会调用superdispatchTouchEvent方法的内部是调用了其内部类DecorView的superdispatchTouchEvent,而DecorView又会调用dispatchTouchEvent去进行事件分发,如果不拦截事件,那么就会继续下传到rootview,rootview中的操作是一样的,同样在dispatchTouchEvent内部调用onInterceptTouchEvent去判断是否拦截,不拦截就会把事件分发给下一个viewgroupA,拦截就直接在onTouchEvent返回true,viewgroupA中做的判断也是一样,最后事件传递到view1,view1是最底层控件,不会有onInterceptTouchEvent,它的选择就只有处理和不处理,处理就在onTouchEvent进行处理并返回true,不处理的话事件也不会被销毁,view1这时会把事件回传,经过上述流程后回传给activity,如果Activity还不处理,那么这个事件才会被销毁;
5、自定义控件
-
自定义View
-
都有哪些自定义View(继承现有view、拼接现有view、完全自定义)
-
自定义View有哪些注意事项
-
View的绘制流程(mesure、layout、draw)
(1) onMesure():测量视图大小,从顶层父View到子View递归调用mesure方法。
(2) onLayout():确定View位置,进行页面布局。从顶层父View向子View递归调用view.layout方法的过程,即父View根据上一步mesure子View所得到的布局大小和布局参数,将子View放在核实的位置上。
(3) onDraw():绘制视图,ViewRoot创建一个Canvas对象,然后调用onDraw()(绘制视图的背景、保存画布的图层、绘制view的内容、绘制view子视图,如果有的话、还原图层、绘制滚动条) -
invalidate、postinvalidate和requestlayout的区别
-
查看:https://blog.csdn.net/lmj623565791/article/details/24252901
查看: http://blog.csdn.net/qinjuning/article/details/7110211
android已经为我们提供了很多控件,但是大多数控件功能都比较单一简单,不能满足我们的需求,我们可以通过自定义控件的方式来实现自己想要的功能。Android实现自定义控件的方式一般有三种,第一种是继承现有的控件,重写相应的方法来扩展该控件的功能;第二种是继承View类或者ViewGroup类,通过onDraw方法绘制控制,然后通过onMeasure方法设置控件的显现,最后为自己绘制的控件设置监听;第三种是通过组合控件来实现自定义控件,譬如说可以自定义一个控件,让它既有ToggleButton的功能,又有ImageView的功能。
自定义控件可以分为两种自定义组合控件和自定义 view。
- 自定义组合控件
自定义组合控件就是把多个控件做为一个整体看待、处理。这样的好处不仅可以减轻 xml 的代码量,也提高了代码的复用性。
自定义组合控件的步骤:
1. 声明一个 View 对象,继承相对布局,或者线性布局或者其他的 ViewGroup。
2. 在自定义的 View 对象里面重写它的构造方法,在构造方法里面就把布局都初始化完毕。
3. 根据业务需求添加一些 api 方法,扩展自定义的组合控件;
4. 希望在布局文件里面可以自定义一些属性。
5. 声明自定义属性的命名空间。比如:xmlns:itheima="http://schemas.android.com/apk/res/com.itheima.mobilesafe"
6. 在 res 目录下的 values 目录下创建 attrs.xml 的文件声明我们写的属性。 7. 在布局文件中写自定义的属性。
8. 使用这些定义的属性。自定义 View 对象的构造方法里面有一个带两个参数的构造方法布局文件里面定义的属性都放在 AttributeSet attrs,获取那些定义的属性。
- 自定义 view
自定义 View 首先要实现一个继承自 View 的类。添加类的构造方法,通常是三个构造方法,不过从 Android5.0开始构造方法已经添加到 4 个了。override 父类的方法,如 onDraw,(onMeasure)等。如果自定义的 View 有自己的属性,需要在 values 下建立 attrs.xml 文件,在其中定义属性,同时代码也要做修改。
2、请描述一下 View 的绘制流程
整个 View 树的绘图流程是在 ViewRoot.java 类(该类位于 Android 源码下面:
D:\AndroidSource_GB\AndroidSource_GB\frameworks\base\core\java\android\view)的
performTraversals()函数展开的,该函数做的执行过程可简单概况为根据之前设置的状态,判断是否需要重新计
算视图大小(measure)、是否重新需要安置视图的位置(layout)、以及是否需要重绘 (draw),其框架过程如下:
1 、 mesarue() 过程
主要作用:为整个 View 树计算实际的大小,即设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:mMeasureWidth),每个 View 的控件的实际宽高都是由父视图和本身视图决定的。
具体的调用链如下: ViewRoot 根对象的属性 mView(其类型一般为 ViewGroup 类型)调用 measure()方法去计算 View 树的大小,回调 View/ViewGroup 对象的 onMeasure()方法,该方法实现的功能如下:
1、设置本 View 视图的最终大小,该功能的实现通过调用 setMeasuredDimension()方法去设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:mMeasureWidth)。
2 、如果该 View 对象是个 ViewGroup 类型,需要重写该 onMeasure()方法,对其子视图进行遍历的measure() 过 程 。 对 每 个 子 视 图 的 measure() 过 程 , 是 通 过 调 用 父 类 ViewGroup.java 类 里 的measureChildWithMargins()方法去实现,该方法内部只是简单地调用了 View 对象的 measure()方法。
2 、 layout 布局过程
主要作用:为将整个根据子视图的大小以及布局参数将 View 树放到合适的位置上。
具体的调用链如下:
1、layout 方法会设置该 View 视图位于父视图的坐标轴,即 mLeft,mTop,mLeft,mBottom(调用setFrame()函数去实现)接下来回调 onLayout()方法(如果该 View 是 ViewGroup 对象,需要实现该方法,对每个子视图进行布局)。
2、如果该 View 是个 ViewGroup 类型,需要遍历每个子视图 chiildView,调用该子视图的 layout()方法去设置它的坐标值。
3 、draw() 绘图过程
由 ViewRoot 对象的 performTraversals()方法调用 draw()方法发起绘制该 View 树,值得注意的是每次发起绘图时,并不会重新绘制每个 View 树的视图,而只会重新绘制那些“需要重绘”的视图,View 类内部变量包含了一个标志位 DRAWN,当该视图需要重绘时,就会为该 View 添加该标志位。
调用流程 :
1 、绘制该 View 的背景
2 、为显示渐变框做一些准备操作(大多数情况下,不需要改渐变框)
3、调用 onDraw()方法绘制视图本身(每个 View 都需要重载该方法,ViewGroup 不需要实现该方法)
4、调用 dispatchDraw ()方法绘制子视图(如果该 View 类型不为 ViewGroup,即不包含子视图,不需要重载该方法)值得说明的是,ViewGroup 类已经为我们重写了 dispatchDraw ()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。
6、长连接
Android维护长连接需要心跳机制。维护任何一个长连接都需要心跳机制,客户端发送一个心跳给服务器,服务器给客户端一个心跳应答,这样就形成客户端服务器的一次完整的握手,这个握手是让双方都知道他们之间的连接是没有断开,客户端是在线的。如果超过一个时间的阈值,客户端没有收到服务器的应答,或者服务器没有收到客户端的心跳,那么,对客户端来说则断开与服务器的连接重新建立一个连接,对服务器来说只要断开这个连接即可。
所谓的心跳包,就是客户端定时发送简单的信息给服务器端,告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务器端,服务器端回复一个固定信息。如果服务器端几分钟后没有收到客户端信息,则视为客户端断开。比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线,就需要心跳包,定时发包收包。
心跳包之所以叫心跳包,是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。
https://blog.csdn.net/qq_32120667/article/details/77750288
https://blog.csdn.net/maiduoudo/article/details/78780089
例如:为了实现IM通信,android客户端和服务端保持长连接。思路,开启一个线程用来发送心跳包,再开启一个线程读取服务端返回的数据。解析到返回的数据后,该线程发消息到主线程,再次启动该读线程,这样可以避免出现读线程阻塞。
7. 你对Binder机制的理解
https://blog.csdn.net/u013309870/article/details/105328743
https://blog.csdn.net/u013179982/article/details/105476131
IPC原理:IPC指的是进程间通信或者是跨进程通信,指两个进程间进行数据交换的过程。每个Android进程,只能运行在自己进程所拥有的虚拟地址空间。虚拟地址空间对应两个部分,
用户空间和内核空间,不同进程的用户空间是非共享的,但是内核空间是共享的,进程间的通信就是利用了不同进程之间可共享的内核空间来完成的。
Binder原理:Binder机制从组件角度来讲,包含Client、Server、ServiceManager以及Binder驱动。
Client:使用服务的进程。
Server:提供服务的进程。
ServiceManager:服务管理进程,作用是使Client进程可以通过Binder名称获得对应的Server中的Binder引用。
Binder驱动:负责进程间Binder通信的建立、传递、计数和管理等工作。
8、Android 进程间通信的几种实现方式
https://www.cnblogs.com/Jason-Jan/p/8459687.html
https://blog.csdn.net/baidu_29094221/article/details/78852998
进程间通信机制:
- AIDL
-
-
Messenger
-
Bundle
-
ContentPovider
-
Broadcast Receiver
-
文件共享
-
Socket
9、Android下的通信机制
查看:https://blog.csdn.net/doonzhang/article/details/83245011
查看:https://blog.csdn.net/WHB20081815/article/details/67640804
查看:https://blog.csdn.net/qq_41517936/article/details/80886618
查看:https://blog.csdn.net/xiaobangkuaipao/article/details/76793702
查看:https://blog.csdn.net/g984160547/article/details/55049304
10、https加密原理
https://www.jianshu.com/p/e0cfb9eba682
https://blog.csdn.net/fei20121106/article/details/84104843
https://blog.csdn.net/ta_ab/article/details/77984256
11、lrucache原理
https://www.jianshu.com/p/b49a111147ee
https://www.jianshu.com/p/e7843dc350ae
1、ThreadLocal
2、深度搜索和广度搜索
3、Android中android_process多进程的坑
https://blog.csdn.net/jiack50/article/details/53557542
18、EventBus 3.0使用详解
查看:https://blog.csdn.net/itachi85/article/details/52205464
查看:https://blog.csdn.net/hua631150873/article/details/51377131
查看:https://blog.csdn.net/bskfnvjtlyzmv867/article/details/71480647
查看:https://blog.csdn.net/u012317510/article/details/78935720
查看:https://www.jianshu.com/p/f9ae5691e1bb
查看:https://blog.csdn.net/qq_17250009/article/details/51872731
查看:https://blog.csdn.net/ljd2038/article/details/51470734
21、Android内存管理机制
查看:https://blog.csdn.net/l_215851356/article/details/78635431
https://www.cnblogs.com/kexianting/p/8508207.html
- 按home键后fragment状态错乱的原因,怎么解决
-
surfaceView、textureView和view的区别
-
ListView和RecyclerView的优化
-
-
Biemap所占的内存
-
OOM和ANR的分析定位及如何避免
-
Android中线程通信机制(handler、全局变量等)
-
应用中如何进行数据缓存和更新
-
如何进行数据库迁移
-
Android版本适配
-
App或Activity的启动流程
-
你对插件化、组件化和热修复都是怎么理解的
-
你用过热修复框架吗,热修复的原理是什么
-
你对MVC、MVP、MVVM的理解
-
三方框架相关问题
-
Okhttp拦截器是怎么实现的
-
如何使用okhttp缓存网络请求数据
-
Okhttp和volley的区别,你是怎么选择的
-
Glide是怎么缓存图片的
-
Glide缓存图片的key是怎么形成的(图片改变时glide是怎么更新图片的)
-
Glide是怎么感知应用的生命周期的(如何确定什么时候加载图片、什么时候停止加载)
-
LruCache的基本原理(怎么控制缓存大小、怎么实现最近最少原则)
LruCache的主要原理就是把最近使用的对象用强引用存储在LinkedHashMap中,当缓存满的时候,把最近最少使用的对象从内存中移除。LruCache提供了get和put方法来完成缓存的获取和添加
LruCache的核心思想就是维护一个缓存对象的列表,列表的排列方式是按照访问顺序来进行排列的,就是将一直没有访问的对象放在队尾,当缓存区满时最先淘汰,将最近访问的对象放在队头,最后淘汰。而LinkedHashMap刚好可以实现这个功能,LinkedHashMap的构造函数中的accessOrder设置为true表示用访问顺序来排序,false表用用插入顺序来排序。
当LruCache调用put方法的时候,就会在集合中添加元素,并调用trimToSize方法判断缓存是否已满,如果满了就调用LinkedHashMap的迭代器删除近期最少访问的元素。当调用get方法的时候,会调用LinkedHashMap的get方法获取集合中的元素,同时通过删除原有元素,更新该元素到队头。 -
RxJava的基本原理
-
RxJava是如何切换线程的
-
数据库框架使用的是哪个?选择他的原因
-
如何进行数据库迁移
-
如何动态请求权限,使用的是什么框架
-
自己如何去封装一个网络请求、图片加载框架,有哪些需要注意的
-
- 稳定性(内存优化、崩溃分析)
- Memory Monitor、MAT、LeakCanary等工具分析内存泄漏并优化
- LeakCanary的原理(基于MAT,在ondestory方法调用后获取activity对象,如果不能被系统回收,并对他进行分析,查找内存泄漏原因)
- 流畅性(渲染优化、冷启动优化、减少主线程数据处理)
- 布局优化(减少嵌套、使用ConstraintLayout、使用include、merger、viewStub等标签、减少wrapcontent使用、删除无用属性)
- 冷启动优化(放置窗口背景图、异步或延后加载非必要数据)
- 动画优化(启动硬件加速、使用vector动画、使用motionlayout、使用lottie等)
- bolckCanary的原理(监测Main Lopper分发message耗时情况)
- 损耗性(流量、电量)
- 使用battery monitor进行电量分析,监测充电状态,在充电状态下做一些耗电操作
- 图片压缩(不同网络环境下请求不同清晰度的图片)
- 压缩网络请求数据,减少流量消耗
- 包瘦身
- 图片压缩(大图压缩、使用webP格式)
- 代码混淆、对齐(zip align)
- 资源优化(删除无用资源、三方库版本统一)
- 插件化处理(将部分模块放置在服务器中)
- 稳定性(内存优化、崩溃分析)
18.集成三方支付宝支付
流程图:
19. Android v4、v7、v13 的区别
Android Support v4: 这个包是为了照顾1.6及更高版本而设计的,这个包是使用最广泛的,eclipse新建工程时,都默认带有了。
Android Support v7: 这个包是为了考虑照顾2.1及以上版本而设计的,但不包含更低,故如果不考虑1.6,我们可以采用再加上这个包,另外注意,v7是要依赖v4这个包的,即,两个得同时被包含。
Android Support v13 :这个包的设计是为了android 3.2及更高版本的,一般我们都不常用,平板开发中能用到。
1、为什么还要用V7呢?V4向下兼容的版本不是更多吗?
V7版本不是为了提供一些V4提供不了的内容,它不是补丁。V7以后你如果创建一个工程,它给你创建的都是FragmentActivity了。 也就是说,以后Android开发所有的界面都可以是碎片模式了。 V7是一种新的框架和更优解决方案.
Android-support-v4 v7 v8 v13 v17 的区别和特性说明
- Android 架构思考(模块化、多进程)
http://blog.spinytech.com/2016/12/28/android_modularization/
- Android 热修复
http://mp.weixin.qq.com/s/GuzbU1M1LY1VKmN7PyVbHQ
- Android 性能优化
http://www.jianshu.com/p/b3b09fa29f65
- Android 动态加载
http://www.jianshu.com/p/b3b09fa29f65
- Android AOP
http://mp.weixin.qq.com/s/SyFe2CgKW51ROAcFHd0a5Q
- MVP+Retrofit+RxJava 网络请求框架
http://www.jianshu.com/p/7b839b7c5884
http://www.cnblogs.com/baronzhang/p/6442047.html
注意:进入该网页后可能需要点击 back 键才能看到正文。
- Android 进程保活
http://www.jianshu.com/p/1da4541b70ad
- Android 状态栏