Android Framework 源码阅读技巧
背景市面上大部分 Android Framework 相关书籍刚开始都是搭建开发环境,下载相关源码。但是相关下载内容一般都是过时的,这一步往往劝退了很多人,曾经我也是。所以这里给出了一种新的阅读源码的方式:VSCode + Ctags。
Android 源码下载:https://android.googlesource.com/platform/frameworks/base/
配置配置 Ctags
ctags 仓库地址:https://github.com/universal-ctags/ctags
配置步骤:
123456$ git clone https://github.com/universal-ctags/ctags.git$ cd ctags$ ./autogen.sh$ ./configure --prefix=/where/you/want # defaults to /usr/local$ make$ make install # may require extra privileges depending on where to install
存在的问题 ...
UETool - Background 字段解析扩展
背景本篇是对上一篇 UETool 的扩展,主要是在其基础上添加对 GradientDrawable 的解析。先看看当前 UETool 对 background 属性的解析:
这里的解析是不完善的,GradientDrawable 对应的是一个 Xml 资源文件,真正的解析应该是给出这个 Xml 文件的具体内容。这就引出了本文的要解决的问题,如何解析 GradientDrawable?
1.关于 Drawable 及其子类的知识参考官方文档:可绘制对象资源2.关于 ShapeDrawable 和 GradientDrawable 的疑问可以参考:Android的ShapeDrawable和GradientDrawable源码解析3.Shape Xml 属性详解:【Android Drawable系列】- shape xml属性详解4.Drawable 详解:Android 中的 Drawable
GradientDrawable 解析Shape 文件语法123456789101112131415161718192021222324252627282930313233343536< ...
UETool - 源码解析
UETool 仓库地址:https://github.com/eleme/UETool ,UETool 的功能很多,这里主要是分析 catch 功能
起步分析
图 1 中圈住的控制面板对应 UETMenu 文件,当点击 catch 的时候会启动一个透明的 Activity - TransparentActivity,注意这里无痕迹的启动动画。
TransparentActivity 启动需要传递一个参数:type,你想使用控制面板中的哪一个功能就传递哪一个 type,TransparentActivity 会根据 type 来选择初始化具体的 CollectViewsLayout 子类实例。
以 catch 功能为例,传递的 type 是 TransparentActivity.Type.TYPE_EDIT_ATTR,就会初始化 EditAttrLayout 实例,并加入 TransparentActivity 的布局中。
TransparentActivity 启动之前,UETool 单例也会保存一份对当前顶层 Activity 。
不论什么 type 传入 Transpare ...
最近使用的取巧实现
背景工作中经常会遇到 最近 等类似功能,这些功能都需要保存相应的对象信息,但是由于这些对象在每次重新启动后都会再次初始化加载到内存中,可以通过只保存对象的某种唯一标志简单快速实现 最近 等类似功能。
原理
当需要保存 最近 对应的对象信息时,只保存对象的 key 信息,将 key 集合信息通过 , 连接转换成一个字符串后,通过 SP 保存
当 App 初始化 最近 相关的对象时,将这些对象根据 key 保存在一个 Map 中
当需要加载 最近 信息时,根据 SP 中存储的 key 信息和上面 Map 中存储的对象信息可以得出想要的 最近 对应的对象信息
实现基类1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768open class XLItemStore(private val context: Context, private val storeKey: String) { ...
Kotlin 的反射
反射简介什么是反射反射(Reflection)机制可以在运行时访问 Java 对象的构造方法、属性、方法。相关的类都在 java.lang.reflect 包下。重要的类有:
Class
Member
Constructor
Field
Method
Array
Modifier
反射的应用场景
开发通用框架:比如 Spring,为了保证框架的通用性,它们可能需要根据配置文件去加载不同的类,调用不同的方法,这个时候就需要用到反射、
动态代理:在切面编程(AOP)中,需要拦截特定的方法通常通过动态代理实现,这就会用到反射技术。
注解:注解本身只是起到标记作用,它需要利用反射机制,根据注解标志去调用注解解释器执行行为。
Java Hook:利用反射和动态代理机制可以实现 Java 层次的 Hook,具体参考:Java基础:基于反射和动态代理的Hook
反射的缺点
性能开销大:具体有哪些性能开销可以参考:反射的性能开销都在那
不安全:反射调用的时候可以忽略权限检查,可能会导致安全问题
内部曝光:反射可以调用私有方法或者字段,所以反射的使用可能会导致意想不到的副作用。
反射的原理了解反 ...
Kotlin 的泛型
Java 中的泛型
关于 Java 中泛型的使用可以参考:Java-泛型
Effective Java 中的泛型要点术语介绍
术语
示例
类型参数
E
泛型
List
参数化类型
List
原生态类型
List
无限制通配符类型
List<?>
有限制通配符类型
List<? extentds Object>
有限制通配符类型
List<? super Object>
有限制类型参数
List
不要使用原生态类型声明中具有一个或者多个类型参数的类或者接口就是泛型类或者泛型接口,泛型类和泛型接口统称为泛型。
每个泛型都对应一个原生态类型,即不带任何实际类型参数的泛型名称,例如 List<E> 对应的原生态类型是 List。原生态类型 List 和 Java 平台没有泛型之前的接口类型 List 完全一样。
没有泛型之前,你可以向原生态类型中添加任何类型的数据,并且可以成功编译运行,直到获取其中的数据并将其强制转化为指定的类型时才会出错。
使用泛型相比之前,有以下好处:
错误前置,可以将运行时错误 ...
Kotlin 的内联
变量内联Java 中有个概念叫做编译时常量—Compile-time Constant,直观的说就是这个变量是不变的,编译器在编译期间就可以确定这个变量的值。具体到代码上,就是这个变量需要是 final,并且只能是基本类型或者字符串。
这种编译时常量,会被编译器以内联的形式进行编译,也就是直接那你的值去替换调用处的变量名来编译。这样一来,程序结构就会变得简单,编译器和 JVM 也方便做各种优化。
这种编译时常量,到了 Kotlin 中有一个转有的关键字叫 const:一个变量如果以 const val 开头,它就会被编译器当做编译时常量进行内联式编程。
12345const val name = "jack"fun main() { println(name)}
上面的代码实际编译是下面这样子的:
123fun main() { println("jack")}
函数内联inline让变量内联的是 const,除了变量,Kotlin 还添加了对函数内联的支持。在 Kotlin 中,你可以给一个函 ...
Kotlin 的高阶函数、匿名函数和 Lambda
高阶函数在说高阶函数之前我们先说一下如何在 Java 的方法中传递函数?Java 本身是不支持直接传递函数的,但是有一种间接的方式—接口,例如:
1234567OnClickListener listener = new OnClickListener() { @Override void onClick(View v) { // doSomething }};view.setOnClickListener(listener);
其实这里只是想要一个 onClick 方法,但是限于语言的问题,这里不得不通过实现 OnClickListener 接口的方式来传递 onClick 方法。
Kotlin 支持传递函数类型,需要说明的是函数类型不是一种类型而是一类类型。对于函数类型,需要指明参数类型和返回值类型,例如:
12345678fun test(hello: (String) -> Unit) { // nop}// (String) -> Unit 对应的函数fun hell ...
Kotlin 的扩展
扩展属性例如,给 Float 扩展一个 int 属性:
1234val Float.int get() = this.toInt() val test = 13.0f.int
扩展函数使用12345678910package com.xl.testfun Int.formatString(format: String): String { return String.format(format, this)}printlin(4.formatString("current value = %d"))//结果current value = 4
扩展函数属于谁?属于函数左边的类吗?并不是,这里的扩展函数是一个顶层的,它谁也不属于,它只属于它所在的 package。
为什么可以被这个类调用呢?因为我们在这个函数限定了一个 Receiver,也就是函数左边的那个类。
作用域扩展函数可以写在方法,类,顶层中,例如:
12345678910111213141516171819202122//方法fun test() { ...
Kotlin 的使用问题
构造函数我们先来看一段 Java 代码:
123456789101112131415161718192021222324252627public class Test { public int id; public String name; { System.out.println("before Test"); } public Test(int id, String name) { System.out.println("on Test"); this.id = id; this.name = name; } { System.out.println("after Test"); } public static void main(String[] args) { new Test(1, "test ...