Android基础学习(一)

来源:互联网 发布:windows 大数据 编辑:程序博客网 时间:2024/04/28 20:44

最近我感觉自己主要作为一个Android程序员基础还有待加强,结合自己在知乎上看到一位朋友提到的:

会写Activity,但对于Activity的生命周期一知半解,对于DecorView、PhoneWindow、ViewRootImpl等关系更一无所知。
会写简单的自定义VIew,但不懂View的Traversal机制(甚至说不出invalidate()的意义),不懂事件传递逻辑,基本上更说不出自定义动画卡顿的优化思路。
知道一堆开源框架:知道Eventbus,但说不清什么是事件总线;用过Retrofit,但搞不懂反射、动态代理是什么;用过Dagger2,但完全没听过Java annotation processor是什么,甚至都没好奇过build/generated包下的代码咋生成出来的;用过realm,但是连Sql语句都写不顺溜。

在这里这位朋友强调了“知其然,还要知其所以然”。所以我特意在这里准备就把自己常用的几个框架通过查阅资料进行深入的学习。这里主要是一篇知识点的总结与学习的笔记。

Android生命周期

Android生命周期

DecorView、PhoneWindow、ViewRootImpl

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
public class PhoneWindow extends Window implements MenuBuilder.Callback {
public final class ViewRootImpl implements ViewParent,        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

均为26.1.0版本的代码

Activity并不负责视图控制,它只是控制生命周期和处理事件。真正控制视图的是Window。一个Activity包含了一个Window,Window才是真正代表一个窗口。
从这里可以看出,DecorView继承自FrameLayout,PhoneWindow继承自Window。下面直接总结这三个类:
(1)DecorView是Activity中的顶级View,居于最外层。Window(PhoneWindow是Window的子类,Window类是抽象类)是视图的承载器,内部持有一个 DecorView。
(2)Window是一个抽象类,实际在Activity中持有的是其子类PhoneWindow。
这里写图片描述

PhoneWindow中操作了DectorView:

// This is the top-level view of the window, containing the window decor.private DecorView mDecor;

(3)ViewRootImpl 是实现 View 的绘制的类,里面有三个方法是关键:

private void performTraversals() {private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,            int desiredWindowHeight) {

自定义View(Traversal机制和invalidate())

作为Android程序员,大家都做过自定义View,他的主要函数执行顺序是(较为粗略的描述):(1)View:onMeasure()->onDraw() (2)ViewGroup:onMeasure()->onLayout()->onDraw()
Traversal机制:View的整个绘制流程是在ViewRoot中的performTraversals()方法展开的。该方法就是Android系统View树遍历工作的核心。其执行过程就是判断是否需要计算视图大小(measure)、是否需要重新安置视图的位置(layout),以及是否需要重绘(draw)视图。
invalidate()方法:请求重绘View树,假如视图大小没有变化就不会调用layout()过程,并且只绘制那些“需要重绘的”
视图。

事件传递逻辑

Android的事件传递在我之前的笔记里有过相应的记录,这里只是简单的把知识点拎出来一下。
事件分发的本质是将MotionEvent向某个View进行传递并最终得到处理。这个事件传递的过程就是分发过程。一个点击事件产生后,传递顺序是:Activity(Window) -> ViewGroup -> View。ViewGroup的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。View的相关事件只有两个:dispatchTouchEvent、onTouchEvent。
对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用;如果这个ViewGroup的onInterceptTouchEvent方法返回false就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直到事件被最终处理。
无论是dispatchTouchEvent还是onTouchEvent,如果返回true表示这个事件已经被消费、处理了,不再往下传了。在dispathTouchEvent的源码里可以看到,如果onTouchEvent返回了true,那么它也返回true。

自定义动画卡顿优化

为了避免UI显得卡顿,你必须确保动画能够保持在60fps。
为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view
同样地,我可以启动硬件加速。从Android 3.0开始,Android的2D图像系统可以通过GPU (Graphics Processing Unit))来加速。GPU硬件加速可以提高许多程序的性能。

Android事件总线

android自带的广播机制对于组件间的通信而言,使用非常繁琐,通信组件彼此之间的订阅和发布的耦合也比较严重,更重要的是对于事件的定义,广播机制局限于序列化的类(通过Intent传递),不够灵活。
一般的事件总线的组成如下:
1.事件类,这是要传递的事件对象。
2.事件总线,是中心控制节点,负责管理事件的注册,接收发布的事件,并完成事件匹配以进行事件处理。
3.发布者,负责分发事件。
4.订阅者,负责事件处理并注册到事件总线。

EventBus是一款针对Android优化的发布/订阅事件总线。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅,以及将发送者和接收者解耦事件总线模型不能完全替代广播机制,因为广播机制可以完成跨App间组件调用。

Retrofit(反射、动态代理)

Retrofit是我们目前最常用的Android网络库,在其中使用了代理这种模式。
代理是一种设计模式,分为静态代理与动态代理。
动态代理是java中的字节码生成技术。通过接口生成代理类,并将代理类的实现交给 InvocationHandler 作为具体的实现。Retrofit中为了简化复杂的网络请求,通过动态代理去处理解析与拼装,可以看成为一种基于元编程开发的解释器。动态代理借助java的反射特性,通过易写的接口与注解,帮助用户自动生成实际的对象,接口中方法真正的调用交给InvocationHandler。可以看出动态代理本质上是生成大量样板代码的过程。

Java annotation processor

我在项目中使用了Butterknife,而Annotation Processor是Butterknife框架实现机制的核心要点。我们就能在编译时根据注解动态生成代码,执行与注解关联的逻辑。我自己曾经写了一个简单的库:https://github.com/Froyo91/SimpleAnnotation,可能自己运行时注解的时候效率会比较低。编译时扫描和处理注解(主要是编译时注解)。一个注解的注解处理器,以Java代码(或者编译过的字节码)作为输入,生成文件(一般是.java文件)作为输出。通过Annotation Processor,我们获取到注解,然后再生成相关Java代码。

build/generated包下的代码咋生成出来的

我们平时使用Android Studio打包,发现build/generated下会生成一些代码,例如:
这里写图片描述

build目录下一般由4个子目录组成:

generated 由aapt工具根据资源数据自动生成的java类(最具代表性的,R.java文件)
intermediates 中间过程
outputs 输出结果
tmp 编译日志

realm

realm是一个移动端的数据库。Realm不是基于SQLite的ORM,它是基于C++ 存储引擎的。所以,它的速度相当来说比较快的,但是目前它也引发了应用的安装包大小问题。在这里只是强调一下,就是除了对库的使用,基本的SQL语句还是要适当掌握一下的。

以上都是自己一些简单的笔记,有些地方难免会过于简单,不过我把自己参考的资料都列在下面了:

https://github.com/xxv/android-lifecycle
https://www.zhihu.com/question/54793295/answer/141136900
http://www.jianshu.com/p/687010ccad66
http://blog.csdn.net/yanbober/article/details/46128379
https://www.jianshu.com/p/faeefc692ae5
http://www.cnblogs.com/carbs/p/5319701.html
http://www.jianshu.com/p/01a239295887
http://www.jianshu.com/p/a56c61da55dd
http://www.jianshu.com/p/d31ae166069e
http://www.maiziedu.com/wiki/android2/process/
http://blog.csdn.net/shareye1992/article/details/50789216
http://www.jianshu.com/p/c223b993b1ec
http://www.jb51.net/article/105822.htm
http://www.jianshu.com/p/8766babc40e0
http://www.jianshu.com/p/e42b638944ae
http://www.jianshu.com/p/90173fc5745b
http://www.jianshu.com/p/a559dafc7173
http://threezj.com/2015/12/17/Android%20View%E6%80%BB%E7%BB%93/
http://blog.csdn.net/aaa2832/article/details/7849400
http://blog.csdn.net/qinjuning/article/details/7110211
http://blog.csdn.net/carson_ho/article/details/54136311
http://blog.csdn.net/yanzi1225627/article/details/22592831
http://hukai.me/android-training-course-in-chinese/ui/custom-view/optimize-view.html
https://segmentfault.com/a/1190000004312745
http://www.cnblogs.com/bbqzsl/p/5926591.html

如果哪里有不足,请告知我~