发现现在某些所谓的「面向小白」的大 V 真是喜欢装逼。例如在某回答里说自己读大学时刷完所有 LeetCode,然后评论中被质问就改口说只刷完 Easy 和 Medium,再后来大概虚心了,直接把这段描述给全删了……
拜托,你能把 Easy 每道不落全刷完我都不太相信好么,有些标着 Easy 的题根本就可以归到 Medium 或 Hard 里去了。
发现现在某些所谓的「面向小白」的大 V 真是喜欢装逼。例如在某回答里说自己读大学时刷完所有 LeetCode,然后评论中被质问就改口说只刷完 Easy 和 Medium,再后来大概虚心了,直接把这段描述给全删了……
拜托,你能把 Easy 每道不落全刷完我都不太相信好么,有些标着 Easy 的题根本就可以归到 Medium 或 Hard 里去了。
去年开源了一个项目(当初花了很大心血),结果今天在 Github 上就搜到有国人去掉了版权说明并进行二次开发,真尼玛啊……
Java 是最贴近 JVM 的语言,只要在对性能还有要求的情况下,Java 依旧是 JVM 上的首选。
事实上在对任何语言进行选择时,都是基于对运行效率和开发效率之间的权衡。所以在我看来 Kotlin 是不可能取代 Java 的(官方也从未立意过要取代),但表达能力更强的 Kotlin 在一些地方肯定会比 Java 更适合,例如一些更高层的逻辑。我觉得就会像 Unity3D 引擎用 C/C++ 来写,但是游戏逻辑会选择用 C# 一样。
DSL 的存在是必要的,但是是否应该给予普通人创建 DSL 的捷径确实有待商榷,毕竟不是所有人是领域或语言大师,过多的 DSL 只会造成干扰。
昨天一天的下载突然上涨了很多。

被智子锁禁锢了多年的 Android 开发玩家终究有了解脱。要知道 Java 是语言界中十分保守的一门语言,大多数 Android 开发者对语言界流行 Feature 缺乏认识,例如对 FP 毫不了解,而实际上 FP 近年来被逐渐证明很适合解决前端的一些问题,这直接导致了大多数人对 Android 开发的理解只停留在三方库应用的层面上。而 Google 这支强心针打得正是时候,这次钦定必然掀起一股浪潮,让更多人对现代语言以及语言思想有所感知。
GC 的设计会是个难关,对 Jetbrains 能否有这样的实力表示担心。当然如果最终能取得成功的话,那用 Kotlin 开发 iOS 估计也不是什么大问题了,Android 端也应该也可以直接用 Kotlin 来写 Native 库了。
撑住啊,超载鸡手办还没入手呢……
Kotlin 1.1 正式版是个令人激动的版本,具体的更新细节可以查看官方博文:Kotlin 1.1 Released with JavaScript Support, Coroutines and more
该来的还是来了。虽然对于 android 来说 coroutine 应该不常用到,coroutine 更适合用在 server 这种 io 密集的应用上。
coroutine 做的其实就是在单线程里替换掉所有 thread.sleep() 函数。例如把 thread.sleep() 换成 asyncio.sleep()。当你需要延时的时候,为什么要调用 thread.sleep() 来阻塞线程呢?还不如用 cpu 来执行程序里的其他代码。所以它把所有 thread.sleep() 替换成 asyncio.sleep(),把所有包含 thread.sleep() 的其他函数(最常见的就是 io 函数)替换成非阻塞的版本。当调用到 asyncio.sleep() 时实际上并不是执行 thread.sleep(),而是保存当前栈然后去执行其他代码,等到恰当时机时再恢复栈继续执行之前的函数。
说起来 coroutine 的实现其实和 android 里的 looper 有点类似,android 是借助 looper 来在单线程里实现异步的,例如 postDelay(),它没有在 postDelay() 里调用 thread.sleep() 来延时,而是把实际要执行的代码扔到事件队列中,等到合适的时机再执行相应的代码,它保证了不会阻塞当前的 main thread。
Running on multiple platforms is a strategic direction for Kotlin. With 1.1 we can run on servers, desktops, Android devices and browsers, but in the future we are going to compile Kotlin to native code and run on many more platforms (including, for example, iOS and embedded devices).
kotlin 未来有望支持编译成 native code,这是个让人十分 excited 的消息。现在已经能将 kotlin 编译成 js 了,未来能编译成 native code 的话,以后你写的代码有望在不借助 jvm 的情况下跑在各个平台下(例如 iOS)。显然 jetbrains 在做一件野心很大的事情,它在尝试让 kotlin 变成更通用的语言。
至于 android 领域,我觉得 android 开发者们现在可以尝试下这门语言了。不用纠结于 google 是否会提供官方支持,按 kotlin 目前的成熟度(要知道 jetbrains 的 ide 技术是世界顶尖的),已经不需要 google 官方给出什么支持了(当然,推广上的支持除外)。虽然国内的开发者可能感觉不到 kotlin 的热度,但是在 reddit 的 android dev 板块上 kotlin 一直是火爆的话题,很多开发者甚至团队都已经用了很长一段时间了。
该来的还是来了。虽然对于 android 来说 coroutine 应该不常用到,coroutine 更适合用在 server 这种 io 密集的应用上。
coroutine 做的其实就是在单线程里替换掉所有 thread.sleep() 函数。例如把 thread.sleep() 换成 asyncio.sleep()。当你需要延时的时候,为什么要调用 thread.sleep() 来阻塞线程呢?还不如用 cpu 来执行程序里的其他代码。所以它把所有 thread.sleep() 替换成 asyncio.sleep(),把所有包含 thread.sleep() 的其他函数(最常见的就是 io 函数)替换成非阻塞的版本。当调用到 asyncio.sleep() 时实际上并不是执行 thread.sleep(),而是保存当前栈然后去执行其他代码,等到恰当时机时再恢复栈继续执行之前的函数。
说起来 coroutine 的实现其实和 android 里的 looper 有点类似,android 是借助 looper 来在单线程里实现异步的,例如 postDelay(),它没有在 postDelay() 里调用 thread.sleep() 来延时,而是把实际要执行的代码扔到事件队列中,等到合适的时机再执行相应的代码,它保证了不会阻塞当前的 main thread。
Running on multiple platforms is a strategic direction for Kotlin. With 1.1 we can run on servers, desktops, Android devices and browsers, but in the future we are going to compile Kotlin to native code and run on many more platforms (including, for example, iOS and embedded devices).
kotlin 未来有望支持编译成 native code,这是个让人十分 excited 的消息。现在已经能将 kotlin 编译成 js 了,未来能编译成 native code 的话,以后你写的代码有望在不借助 jvm 的情况下跑在各个平台下(例如 iOS)。显然 jetbrains 在做一件野心很大的事情,它在尝试让 kotlin 变成更通用的语言。
至于 android 领域,我觉得 android 开发者们现在可以尝试下这门语言了。不用纠结于 google 是否会提供官方支持,按 kotlin 目前的成熟度(要知道 jetbrains 的 ide 技术是世界顶尖的),已经不需要 google 官方给出什么支持了(当然,推广上的支持除外)。虽然国内的开发者可能感觉不到 kotlin 的热度,但是在 reddit 的 android dev 板块上 kotlin 一直是火爆的话题,很多开发者甚至团队都已经用了很长一段时间了。
初中时候的班主任是语文老师,人特别苛刻,我和那时候的挚友都十分讨厌她。于是我突发奇想,用 vb6 写了个定时触发主板 beep beep 响的 exe 放到课室电脑的启动项中。
结果就是一上语文课电脑就会 bb 响,老师怎么调音量都还是会响(因为是主板发声)。但是碍于要放 ppt 只能任它响一整节课……
后来玩了几节课后我就把它删了
RxJava 是 Android 开发中的一件神器,但我们在 Activity 或 Fragment 里使用 RxJava 的时候要注意,没在恰当时机执行 Dispose 或终止 Observable 的话会导致内存泄漏。下面这段代码中,Consumer 匿名内部类持有 Activity 的引用,当 Activity 销毁时 Observable 并没有被中止或切断与 Observer 的联系(未 Dispose),所以就造成了内存泄漏。
Observable.interval(0, 2, TimeUnit.SECONDS)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long n) throws Exception {
}
});
要避免这种情况的话,我们可以使用 Rx 官方提供的 Dispose 方法来在 Activity 销毁时手动切断 Observable 与 Observer 的联系(但是 Observable 还会继续发射数据):
private Disposable disposable;
@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
disposable = Observable.interval(0, 2, TimeUnit.SECONDS)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long n) throws Exception {
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
disposable.dispose();
}
这样写的体验是割裂的,你需要保存一堆 Disposable 的引用(当然你也可以使用 CompositeDisposable),然后在销毁时再「手工进行」Dispose。
有没有更优雅些的办法呢?答案是有的。在 Rx 官方提供的一些操作符中可以让我们提前中止 Observable 与 Observer 的联系,例如 TakeUtil 操作符:

假设 Observable.takeUtil(ObservableB).subscribe(Observer) 。当 ObservableB 发射第一个数据时,Observable 立刻被 Complete,同时立刻调用了 Observer 的 onComplete() 方法,观察结束后立刻释放对 Observer 的引用。
于是,脑洞大开的我们可以创建一个如下的变换操作符:
public class BindLifecycleTransformer<T> implements ObservableTransformer<T, T> {
private final BehaviorProcessor<Integer> lifecycleBehavior;
public BindLifecycleObservableTransformer(@NonNull BehaviorProcessor<Integer> lifecycleBehavior) {
this.lifecycleBehavior = lifecycleBehavior;
}
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.takeUntil(
lifecycleBehavior.skipWhile(new Predicate<Integer>() {
@Override
public boolean test(@LifecyclePublisher.Event Integer event) throws Exception {
return event != LifecyclePublisher.ON_DESTROY_VIEW &&
event != LifecyclePublisher.ON_DESTROY &&
event != LifecyclePublisher.ON_DETACH;
}
}).toObservable()
);
}
}
接下来只要在 Activity 里创建一个用于记录当前所在生命周期的 LifecycleBehavior,然后就可以使用 compose(new BindLifecycleObservableTransformer(lifecycleBehavior)) 来绑定你的 Observable 到 Activity 的生命周期上了。
但是这样还是需要手动维护个 LifecycleBehavior。有没有办法连 LifecycleBehavior 都不写呢?答案依然是有的。
我们可以通过一个独立的 HeadlessFragment 来维护 LifecycleBehavior,然后想监听哪个 Activity 或 Fragment 的生命周期的话,只要将 HeadlessFragment 插入其中就行了,FragmentManager 会主动同步 HeadlessFragment 与父 Activity/Fragment 之间的生命周期。
我们将上述的工作封装成了一个开源库 RxLifecycle ⇦猛戳,你可以在其中查阅上面提到的所有代码。它允许你仅用一句话绑定你的 Observable 到 Activity/Fragment 的生命周期上:
Observable.interval(0, 2, TimeUnit.SECONDS)
.compose(RxLifecycle.bind(MainActivity.this).<Long>withObservable())
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long n) throws Exception {
}
});
我们在仓库中还提供了个 DEMO ,以便详细介绍 RxLifecycle 的全部功能。

android 开发中官方选择了使用 xml(layout、drawable 等) 来描述 view。但实际上 xml 的表达能力有限,只用 xml 来描述 view 几乎不可能,它只解决了 ui 中的描述问题,而大部分逻辑问题依然依赖于用代码解决。
你仔细思考下的话会发现目前前端开发的一个相似的套路,使用 html、css、xml 等更具描述能力的 external dsl(domain-specific language )来描述界面,然后使用代码来解决界面上的一些逻辑问题。这些 external dsl 用于将数据配置跟代码逻辑分离开来,它们能让你轻易实现数据的跨语言、夸应用、跨平台,例如你可以用任意一门语言在任意一个系统下再开发个 parser,对 android layout xml 进行再描述。
当然,解析起 xml 来肯定要比直接跑代码慢好几个 level,所以甚至有很多人抛弃 xml,坚持使用 java 来构造布局,但这明显不是一个好的选择。后来一些现代语言加入了 internal dsl 这种东西,它赋予你在代码中写 dsl 的能力:
linearlayout {
textview {
layoutwidth "match_parent"
layoutheight "wrap_content"
text "Hello"
}
}
你不用显式地去构造任何实例,这看起来像在写一些配置。但它和配置不一样,因为你甚至能把逻辑也参杂在里面:
linearlayout {
textview {
// ...
text if (firstword) "Hello" else "World"
}
}
看起来挺棒的是吧?这种感觉有点像在代码里面写 xml、或者在 xml 里写代码(想想官方给出的 databinding)。它同时具备描述能力和逻辑能力。
可以看看代码构建领域的一个例子:maven 和 gradle。以前 maven 加 shell script 的组合,已经开始逐渐被具备写 dsl 能力的 groovy 给取代了。再看看 web 前端吧,之前大热的 reactjs 的 jsx、近期的 binding.scala,它们也都是 dsl 的应用。
那 internal dsl 有缺点么?没法跨语言。想在 android 中尝试 internal dsl 怎么办?赶紧用 kotlin 啊。
另外,kotlin 也有 dsl 的话为什么还需要 groovy?也确实有人有一样的想法:gradle/gradle-script-kotlin