0%

1. 简介

OverScroller 在 Android 系统中承担着为 ListView、RecyclerView、ScrollView 这些滚动控件计算实时滑动位置的任务,这些位置算法直接影响着每一次滚动的体验

众所周知,Android 的动画体验不如 iOS,即便如今 Android 已普遍支持 120Hz 高刷,体验起来也不是非常舒服。究其原因已经不是硬件性能限制,而是其中很多动画设计本身就有问题。苹果早在很早之前就发布了 Designing Fluid Interfaces 致力于打造一个丝滑流畅的用户体验,反观 Android,对于一个日常使用中使用最多的滑动工具类 OverScroller 近几年改进竟然寥寥无几,几乎没有,实在是有点想吐槽

这个系列分为两篇,第一篇主要讲述 Android 实现滚动的核心工具类 OverScroller 的使用方法和原理,第二篇我们将探索如何进行改进,希望我们每一次探索都能给用户体验带来提升

阅读全文 »

1. 简介

从 Android 7 开始,Android 源码编译时默认使用 Ninja,编译时,会先把 makefile 和 bp 转换成 ninja 再进行编译。这个转换过程非常慢(需要遍历处理所有关联的 makefile、bp 文件),即使只是通过 mmmmm 编译某个模块,也会有很多因素触发 ninja 文件的重新生成,而这对基于源码开发的模块很不友好,编译好慢!

阅读全文 »

1. 简介

随着 Android Q 发布,「黑暗模式」或者说是「夜间模式」终于在此版本中得到了支持,官方介绍见:https://developer.android.com/guide/topics/ui/look-and-feel/darktheme,再看看效果图:

2019-10-21-17-21-50.png

其实这个功能魅族在两年前就已支持,不得不说 Android 有点落后了,今天我们就来看看原生是怎么实现全局夜间模的吧

阅读全文 »

1. 简介

使用 Android Studio 查看 Android Framework 代码体验非常好,无论是索引还是界面都让人很满意,但是当你跟踪代码,发现进入 native 逻辑时,就会发现 Android Studio 对 native 代码的支持非常不好,不能索引不支持符号搜索不能跳转等,这些让人非常抓狂。那么如何能在 IDE 愉快地查看 native 代码呢?在 Windows 上,Source Insight 的表现也很好,但苦于只有 Windows 平台支持且界面不好,经过一番折腾,还真是找到了方法,下面我们将一步一步打造丝滑的 native 代码阅读环境。

阅读全文 »

1. 简介

很多 Android 开发者都会希望编译 Android 源码并刷进自己的手机里面,但网上教程很多都仅仅是告诉你 lunch、make 等等,但你手里有一台设备时却发现,你编译出的镜像由于驱动关系是不能直接烧进手机的。这里整理了一下步骤,帮助大家可以按照流程编译并烧写镜像。

阅读全文 »

简介

Protocol Buffers 是 google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用 xml 进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。

至于protobuf是什么、使用场景、有什么好处,本文不做说明,这里将会为大家介绍怎么用 protobuf 来定义我们的交互协议,包括 .proto 的语法以及如何根据proto文件生成相应的代码。本文基于proto3,读者也可以点击了解proto2

阅读全文 »

概述

装饰模式(Decorator)也叫包装器模式(Wrapper),是指动态地给一个对象添加一些额外的职责,就增加功能来说装饰模式比生成子类更为灵活。它通过创建一个包装对象,也就是装饰来包裹真实的对象

情景举例

我们先来分析这样一个画图形的需求:

  1. 它能绘制各种背景,如红色、蓝色、绿色
  2. 它能绘制形状,如三角形,正方形,圆形
  3. 它能给形状加上阴影

就先列这三个简单的需求吧,下面让我们比较下各种实现的优缺点

丑陋的实现

来看看我们用继承是如何实现的,首先,抽象出一个Shape接口我想大家都不会有意见的是不是?

1
2
3
4
5
6
7
8
9
10
/**
* @author HansChen
*/
public interface Shape {

/**
* 绘制图形
*/
void draw();
}

然后我们定义各种情况下的子类,结构如下,看到这么多的子类,是不是有点要爆炸的感觉?真是想想都可怕
2019-9-2-12-35-9.png

而且如果再新增一种需求,比如现在要画椭圆,那么维护的人员估计就要爆粗了吧?

阅读全文 »

场景问题

发送消息

现在我们要实现这样一个功能:发送消息。从业务上看,消息又分成普通消息、加急消息和特急消息多种,不同的消息类型,业务功能处理是不一样的,比如加急消息是在消息上添加“加急”字样,而特急消息除了添加特急外,还会做一条催促的记录,多久不完成会继续催促。从发送消息的手段上看,又有系统内短消息、手机短消息、邮件等等。现在要实现这样的发送提示消息的功能,该如何实现呢?

阅读全文 »

概述

我们执行一个功能的函数时,经常需要在其中写入与功能不是直接相关但很有必要的代码,如日志记录、信息发送、安全和事务支持等,这些枝节性代码虽然是必要的,但它会带来以下麻烦:

  • 枝节性代码游离在功能性代码之外,它下是函数的目的
  • 枝节性代码会造成功能性代码对其它类的依赖,加深类之间的耦合
  • 枝节性代码带来的耦合度会造成功能性代码移植困难,可重用性降低

毫无疑问,枝节性代码和功能性代码需要分开来才能降低耦合程度,我们可以使用代理模式(委托模式)完成这个要求。代理模式的作用是:为其它对象提供一种代理以控制对这个对象的访问。在某些情况下,一 个客户不想直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。

代理模式一般涉及到三个角色:

  • 抽象角色:声明真实对象和代理对象的共同接口
  • 代理角色:代理对象内部包含有真实角色的引用,从而可以操作真实角色,同时代理对象 与真实对象有相同的接口,能在任何时候代替真实对象,代理对象可以在执行真实对 象前后加入特定的逻辑以实现功能的扩展。
  • 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象

常见的代理应用场景有:

  • 远程代理:对一个位于不同的地址空间对象提供一个局域代表对象,如RMI中的stub
  • 虚拟代理:根据需要将一个资源消耗很大或者比较复杂的对象,延迟加载,在真正需要的时候才创建
  • 保护代理:控制对一个对象的访问权限
  • 智能引用:提供比目标对象额外的服务和功能

接下来,我们用代码来说明什么是代理模式

阅读全文 »

概述

在开发过程中,为了实现解耦,我们经常使用依赖注入,常见的依赖注入方式有:

  • 构造方法注入:在构造方法中把依赖作为参数传递进去
  • setter方法注入:添加setter方法,把依赖传递进去
  • 接口注入:把注入方法抽到一个接口中,然后实现该接口,把依赖传递进去

下面用一个小栗子来说明三种方式的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class PersonService implements DependencyInjecter {

private PersonDao personDao;

// 构造方法注入
public PersonService(PersonDao personDao) {
this.personDao = personDao;
}

// setter方法注入
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

// 接口注入:实现DependencyInjecter接口
@Override
public void injectPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

... ...
}
阅读全文 »