2016年5月

前些天公司问我,入职一年要不要什么东西,「比如电脑啥的」。我正好心水 Dell Precision M4800 一阵子了,于是就打算买一台。

奈何考虑到 M4800 型号实在太老,只好考虑升级款 Precision 7510——虽然外观上不那么好看,不那么工程师了,但还算是勉强保留了一些移动工作站应有的硬朗。功能强大,对得起 Precision 这个名头。

经销商在出厂配置基础上进行了提升,换上了 32G 的 DDR4 内存,以及 256G SSD + 1T HDD 的硬盘。最终价格应该在 16500 和 19500 之间,具体没有问公司。

由于配置水平不错,终于不用再用 Xfce 了。拿到机器后先装的 Ubuntu GNOME。然而发现存在一些棱角——大约是 Ubuntu GNOME 还只是 Ubuntu 各 flavor 中较小众的一个;而且 Canonical 实在魔改了很多 GNOME 基础库里的东西。

于是我直接尝试了 Debian unstable (stretch),加 GNOME Shell。工作起来非常舒服。机器性能确实足以应付日常工作——同时开着两个虚拟机、几个 IDE、几十个浏览器标签页的情况下,依然可以秒开 GIMP。

Screenshot-from-2016-05-28-16-05-25.jpg

有了舒服的大显示器、同事送的键盘、新的电脑,有两个喝咖啡的杯子,有喜欢的各种书,还有漂亮的单车备件,办公桌简直完美。

IMG_20160528_171450780_HDR.jpg

不知道是出厂就有问题,还是经销商自己改装的时候弄出的问题,从一拿到机器,键盘中间的 touch stick 就无法使用。不过 Precision 系列送了三年内下一工作日免费上门服务。于是发邮件提 ticket,很快收到回复。第二天小哥就上门维修,花五分钟时间拿出新的键盘总成换上,解决了问题。

Screenshot from 2016-05-30 17-28-56.png

Time for productivity burst!

我想要优化每一个图片的大小,精准地选择文件格式和参数。
我想要每一个像素都对齐,每一个按钮都有合适的 ripple 效果。
但是整个公司根本没有一个人在乎。
所有人只在乎功能更快做完上线。

Android 开发中,用得最常见的 interface 之一便是 OnClickListener 了。不使用 android:onClick 属性的话,自然就不得不去 implement OnClickListener

假设我们不使用任何框架或是架构模式,只是写一个简单的 Activity;在一个 Activity 中有多个可点击的按钮时,我的同事会这么写:

public class ExampleActivity extends Activity implements OnClickListener {

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);

        findViewById(R.id.first_button).setOnClickListener(this);
        findViewById(R.id.second_button).setOnClickListener(this);
    }

    @Override
    public void onClick(final View v) {
        switch (v.getId()) {
            case R.id.first_button:
                // bla bla bla
                break;
            case R.id.second_button:
                // bra bra bra
        }
    }
    
}

事实上,Android 官方有些 sample 里面也是这么写的。然而在我看来,这么写代码是非常不优雅的,因为一个 OnClickListener 的实现,只应该关注和点击事件本身相关的内容,它的含义和 Activity 的含义是截然无关的,让同一个类继承/实现他们,会使得这个类的含义变得不清晰。同时,这样还给 ExampleActivity 类增加了一个 public 的方法,削弱了这个类的封闭性。

所以如果像下面这样,会好不少:

public class ExampleActivity extends Activity {

    private OnClickListener onClickListener = new OnClickListener() {
        @Override
        public void onClick(final View v) {
            switch (v.getId()) {
                case R.id.first_button:
                    // bla bla bla
                    break;
                case R.id.second_button:
                    // bra bra bra
            }
        }
    };

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);

        findViewById(R.id.first_button).setOnClickListener(onClickListener);
        findViewById(R.id.second_button).setOnClickListener(onClickListener);
    }
    
}

这样写体现了 composition over inheritance 的思想。它避免了上面的所有问题,看起来舒服得多。

不过,这样还是让阅读代码时很不方便——看到 onCreate 里面时,还不得不经常滚动到声明 onClickListener 的地方去,并且在 onClick 中艰难地寻找真正和某个特定按钮相关的代码。当然这两个问题之前那个版本也都无法避免。

另一件糟糕的事情是,不同按钮的 listener 逻辑很可能是相对独立的,放到同一个 onClickListener 里,还是很丑陋。

所以为了进一步避免这几个问题,我一向都是用下面这样的写法:

public class ExampleActivity extends Activity {

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);

        findViewById(R.id.first_button).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                // bla bla bla
            }
        });
        findViewById(R.id.second_button).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                // bra bra bra
            }
        });
    }
    
}

这样的话,不同逻辑间相对独立,看起来非常舒服,便于阅读,并且让我找回了写 JavaScript 的舒畅感觉(划掉)。

那么问题来了:为什么有的人不使用最后一种写法呢?

此问题已被提交至 https://segmentfault.com/q/1010000005337426

Recently, I made a decision to disallow programmers to use android:onClick XML attributes to add click event listeners. Existing usages will be removed too. Actually, the attribute itself was a very bad design, considering that web frontend developers has switched from onclick HTML attribute to addEventListener API for a long time.

Here are the real reasons why android:onClick XML attribute should be avoided:

  • If an ancestor element has theme applied, android:onClick no longer works, because the program will look for the click handler from ContextThemeWrapper instead of Activity (see http://stackoverflow.com/questions/29525644/). When applying a theme, programmers may not realize the problem.
  • Android look for the specified method from the parent Activity. When programmers change an Activity into a Fragment, they may be ignoring this problem.
  • To make the two problems above more severe, onClick uses reflection. It therefore prevents the compiler from telling you problems. You app will crash at run time.
  • As it uses reflection, performance will be compromised.
  • Android provides android:onClick attribute, but no android:onChange or any other XML attributes for event listeners. Considering click listeners aren't really different from other event listeners, keeping them consistent will be good.
  • When using android:onClick, one must create a public method with parameter (View view). Android Lint will then complain "unused parameter".
  • Adding a public method is not elegant in any way.

有时候我也在想,为什么我以前无法做到在 Linux 下工作,而现在却能做到。

正好那天和别人谈起,我干脆就列出我用过的所有 Linux 发行版好了。

小学

  • Red Hat 9 / GNOME 2

按道理讲这个不算,因为就装上去用了几天而已。实在不会安装软件。当时主流的软件分发方式还是丢一个 tar 包让你自己编译,于是当时安装 Real Player 都用了很久——而根本没有其它好用的播放器。

初中

  • Fedora 7? / GNOME 2

作为双系统的第二系统。那时候有一台 Athlon 64 2800 处理器的电脑。

高中

  • Ubuntu 9.10? / GNOME 2
  • Xubuntu 10.04? / Xfce
  • Lubuntu 10.04? / LXDE

基本都是作为双系统的第二系统,或是一台老旧的笔记本的唯一系统。那天老旧的笔记本常被我用来写东西和看毛片。

大学

  • Linux Mint ? / Cinnamon
  • Arch Linux / Xfce
  • Linux Mint ? / MATE
  • Xubuntu 13.04? / Xfce
  • OpenSUSE ? / KDE
  • Kubuntu 14.04? / KDE

大学里前后换了三台笔记本。系统也一直在换来换去。Arch 和 SUSE 都很可爱,但是用起来实在不省心。而且 zypperpacman 真的很难用(比起 apt-getyum 来说)。

毕业

  • Xubuntu 15.04 / Xfce
  • Debian 8 / GNOME 3

毕业以后基本没时间折腾了,Xfce 简单、稳定,并且在那台老旧的笔记本上也能舒畅的运行。后来公司发了台好笔记本,于是打算换炫一点的 GNOME Shell。而之前的经历告诉我,网上太多 binary 包都只有 deb 版,于是装 Debian 系的系统是最好的选择。一开始试了试 Ubuntu GNOME,发现中文输入法一直有问题。于是就换了 Debian unstable,很是舒畅。