0. 前言

本文是Real World RxJava系列的第一篇,这个系列主要介绍如何使用RxJava解决Android开发中的一些实际问题。如果你还不了解RxJava的基本概念(Observable, Subscriber, Subscription等),建议先阅读RxJava初探

1. 问题描述

我们首先实现一个Android中最常见的点击按钮,弹出一个新的Fragment的效果,其代码如下。

1
2
3
4
5
6
7
8
9
10
findViewById(R.id.normal_button).setOnClickListener(view -> {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction
.setCustomAnimations(R.animator.slide_up, R.animator.slide_down, R.animator.slide_up, R.animator.slide_down)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

transaction
.add(android.R.id.content, new DummyFragment())
.addToBackStack(DummyFragment.class.getSimpleName()).commit();
});

这段代码存在的问题在于当用户无意中多次点击到按钮时,会弹出多个Fragment,如图所示。

阅读全文 »

原文链接:Tell, Don’t Ask

Alec Sharp在其最近的书Smalltalk by Example[1]中指出了一个极有价值的观点:

过程化的代码获取信息并做出决定。面向对象的代码只是告诉对象去做。
— Alec Sharp

这意味着,你应该尝试直接告诉对象你希望他们去做什么,而不是询问他们的状态,做出决定,再告诉他们去做什么。

这样做的问题是,作为调用者,你不应该根据你获得的被调用对象的状态来做决定, 然后再去改变对象的状态。你实现的这部分逻辑很可能是被调用对象的职责,而不是你的。由你来在对象外部做出决定破坏了它的封装。

当然,你可以说,这是显然的。我从来不会写那样的代码。然而,我们仍然会通过检验一些引用对象,并根据不同的返回值调用不同的方法。但是这也许不是最好的做法。告诉对象你要什么,由它来决定如何做。要用声明式的思考方式,而不是过程式的!

阅读全文 »

0. 前言

之前写过3篇博客分析Philm MVP架构的实现,最近在接触到一些关于clean architecture的话题后,又仔细读了一些关于MVP以及MVVM的文章,觉得当时的一些理解不够深入,因此针对应用架构的理论部分重新做出总结。

1. Model-View-Presenter

Martin Fowler的这篇Retirement note for Model View Presenter Pattern文章明确表明了,这个模式已经“退休”了。作为MVC模式的变形之一,它被重新归纳为了MVC模式的两种变形:Passive View和Supervisor controller。

1.1 Passive View

Passive View是MVC模式的一种变形。对于UI而言,它被分为负责显示的View和接收用户交互的Controller。Passive View是一个完全被动的View,不负责UI更新,因此也不依赖Model。

这种模式强调的是View与Model之间的独立,Controller负责全部的View与Model的同步工作,所有的消息都需要通过Controller传递。

阅读全文 »

0. 前言

Dagger2是首个使用生成代码实现完整依赖注入的框架,极大减少了使用者的编码负担,
本文主要介绍如何使用Dagger2进行依赖注入。如果你不还不了解依赖注入,请看这一篇

1. 简单的依赖注入

首先我们构建一个简单Android应用。我们创建一个UserModel,然后将它显示到TextView中。这里的问题是,在创建UserModel的时候,我们使用了前文所说的hard init。一旦我们的UserModel的创建方式发生了改变(比如需要传入Context对象到构造函数),我们就需要修改所有创建UserModel的代码。而我们希望的是,对于UserModel的修改不影响其他模块的代码(比如这里的MainActivity)。

阅读全文 »

0. 前言

在软件工程领域,依赖注入(Dependency Injection)是用于实现控制反转(Inversion of Control)的最常见的方式之一。本文主要介绍依赖注入原理和常见的实现方式,重点在于介绍这种年轻的设计模式的适用场景及优势。

1. 为什么需要依赖注入

控制反转用于解耦,解的究竟是谁和谁的耦?这是我在最初了解依赖注入时候产生的第一个问题。

下面我引用Martin Flower在解释介绍注入时使用的一部分代码来说明这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MovieLister {
private MovieFinder finder;

public MovieLister() {
finder = new MovieFinderImpl();
}

public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
...
}

1
2
3
public interface MovieFinder {
List findAll();
}
阅读全文 »

0. 前言

为Android中基本的View组建Activity设置转换动画的方式一般有两种:通过overridePendingTransitions设置,以及使用TransitionManager实现。overridePendingTransitions只能使用XML来设置Activity的进入和退出动画,局限性很大。而使用TransitionManager只兼容API level 19及以上的设备。最近在InstaMaterial concept中发现其利用addOnPreDrawListener方法,提供了一种新的Activity转换动画实现方式,这里详细记录下这种基于addOnPreDrawListener()的实现方式。

1. 实现展开动画

首先创建一个基本的Activity转换场景,去掉默认的转换动画,没有任何动画的Activity转换效果如下。

阅读全文 »

0. 前言

在Android开发中,测试是一个很少被提及的话题。在早期,Android并没有一个很好的测试框架,你也很难找到一个测试全面的优秀开源项目。近些年,随着Android社区的成熟,出现了诸如Robotium,Robolectric等的优秀测试框架。而Google也在近期推出了自己的UI测试框架Espresso。

本文基于最简单的Hello World项目进行测试,重点在于介绍Robolectric和Espresso的配置.。项目完整的示例代码在这里

1. 使用Espresso进行Instrumentaion Test

首先创建一个最简单的Android项目,包含一个Hello World的TextView。打开Build Variant,选择Android Instumentation Tests。在build.gradle中配置Espresso,增加的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apply plugin: 'com.android.application'

android {
...
defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

packagingOptions {
exclude 'LICENSE.txt'
}
}

dependencies {
...
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1'
androidTestCompile 'com.android.support.test:runner:0.2'
}

之后点击Gradle同步。

到src/androidTest删除自动生成的ApplicationTest.java,新建MainActivityTest.java如下。这段代码主要是测试Hello world!这段文字是否显示到了界面上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@LargeTest
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {

public MainActivityTest() {
super(MainActivity.class);
}

@Override
public void setUp() throws Exception {
super.setUp();
getActivity();
}

public void testHelloWorldOnView() {
onView(withText("Hello world!")).check(matches(isDisplayed()));
}

}
阅读全文 »

最近在使用豆瓣api仿写一个豆瓣同城的app,过程中遇到了3中界面的跳变,解决方式整理如下。

1. UIPageViewController的内容跳变

这里现象如图所示。

造成这种跳变的原因主要在于,作为UIPageViewController内容的Controller,其View的边界被设置为了父View的margin。如图所示。

阅读全文 »

0.前言

本文主要记录了初步学习RxJava后的总结,希望用最短的篇幅讲清楚RxJava的主要用法。部分内容来自Dan Lew的Grokking RxJava

本文的示例代码在这里

1 基本概念

1.1 Rx结构

响应式编程的主要组成部分是observable, operator和susbscriber(与Dan Lew的文章不同,这里把Operator也做为组成部分介绍,这样对结构的整体性会有更全面的认识)。
一般响应式编程的信息流如下所示:

Observable -> Operator 1 -> Operator 2 -> Operator 3 -> Subscriber

也就是说,observable是事件的生产者,subscriber是事件最终的消费者。

因为subscriber通常在主线程中执行,因此设计上要求其代码尽可能简单,只对事件进行响应,而修改事件的工作全部由operator执行。

1.2 最简单的模式

如果我们不需要修改事件,就不需要在observable和subscriber中插入operator。这时的Rx结构如下:

Obsevable -> Subscriber

这看起来很像设计模式中的观察者模式,他们最重要的区别之一在于在没有subscriber之前,observable不会产生事件。

一个简单的RxJava HelloWorld的代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 创建observable
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello RxJava");
subscriber.onCompleted();
}
});

// 创建subscriber
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onCompleted() {

}

@Override
public void onError(Throwable e) {

}
@Override
public void onNext(String s) {
log(s);
}
};

// 订阅
observable.subscribe(subscriber);

阅读全文 »

原文链接: Improving Comment Rendering on Android

上周,成千上万来自全世界的IG用户齐聚在社区组织的先下聚会 Worldwide InstaMeet11上。WWIM11 是历史上最大,最具地域多样性的Instagram聚会,从Muscat到Bushwick,成千上万用户分享了大约10万张照片。

每月世界上有超过3亿用户每月使用IG,其中65%来自美国以外的国家,无论用户在哪,我们一致致力于让IG更快,更容易使用。自从去年夏天IG重新设计后,我们在继续努力提升性能。

我们最近的一项改进是关于渲染庞大复杂的文本以及如何通过改进它优化IG的feed滚动。我们希望你可以从我们的经验中找到提升自己app速度的方法。

阅读全文 »