首页 > 编程语言 > Android开发 > 为什么你的android代码写得这么乱
2016
03-31

为什么你的android代码写得这么乱

Android上绝大多数的代码,都是由事件触发的,或者说,几乎所有代码都是写在某个回调上的,比如onCreate, onPause, onClick,onBind等等,而这些回调函数,全都是一个个的函数,也就是说,是一个一个小的过程。

单个事件内完成的功能

对于一些简单的情况,在某一个回调内部就能完成的事件,大致上都是在回调中创建一个A类的对象,然后调用A类的某个方法,这个方法里面又用到了B类和C类的对象,经过了一系列翻云覆雨的计算,我们最终得到了一些数据,用TextView显示了出来,比如点击一个按钮弹出一个Toast显示当前软件的版本号这样的功能,只需要一个onClick就可以完成。所以我们可以粗暴的理解为,所有面向对象,都是基于过程的。因为只有一系列对象,按照某种特定的顺序组织起来,调用里面特定的方法,才能得出一个有意义的功能。这也解释了为什么很多SDK,就给你个方法,告诉你,你什么都不用管,在Application的onCreate里面调一下这个方法就好了。


理论上任何一个功能都可以用一个方法来完成

多个事件配合完成的功能

再比如一些稍微复杂一点的功能,需要多个事件配合,比如计算器,当用户按下第一个数字的时候,触发了onClick事件,你要把这个数字保存为activity的某个字段,接着,用户按下了加号和第二个数字,你都要这样保存起来,以便于在最终用户按下等号的时候,你能把以前的一系列输入获取到,以计算出一个结果。也就是说,当一个功能需要多个事件配合完成的时候,我们做的事情就是把各个事件的最终结果从局部作用域提升为类的字段,即提升可见性。当可见性不那么好提升的时候,垃圾代码就出现了。比如这样的代码:


五行缺Context

Context是非常常用的一个对象,无论是发广播,还是启动activity,启动Service,获取SharedPreferences,获取资源等等,许多地方都需要用到context,加上Application对象一直存在,于是就想出了这么个办法。

我并不反对通过提升可见性来实现多个事件之间的配合,比如计算器的例子,提升可见性就是一个简洁优雅的解决方案。但是很多时候为了提升某些字段的可见性,将字段设置为静态字段是没有必要的,而且有可能造成内存泄漏。

什么样的代码简洁清晰

我们之所以代码写得那么难受,很多时候是因为给的接口不够“多”,试想一下,如果SD卡的文件被改动有回调,手机位置发生变化有回调,网络状态一变化就有回调,这会让很多功能实现起来变得非常简单。


封装必要的回调函数

什么事件需要写回调?通常是那些破坏代码简洁的逻辑,比如耗时的操作,像网络请求,大量计算,获取地理位置等,或者一直在被监听的事件,比如推送到本地的消息,文件被篡改、网络状态等。让那些简单不耗时的操作,比如读取文件,弹出Toast或者设置TextView分门别类的放在这些回调里面,让人一目了然。

这些是无法用MVP,MVVM等架构解决的,原因很简单,因为无论怎么分层,这些回调都是需要的,分层只是把这些回调放在不同的文件里面而已。软件分层一方面是为了容易移植,另一方面是为了分离纯Java的代码,方便做单元测试。

回调是让代码简洁的方式之一,在我们实际编码的过程当中,在此前的基础上,还可能会遇到下面这个非常常见的问题。

臃肿的回调

无论我们愿不愿意,我们都是在以填充各种事件的回调来编写android代码的,这就导致一个问题,当业务逻辑越来越复杂的时候,我们就很有可能会在同一个回调中,编写多个毫不相关的任务的业务逻辑。

当一个事件的回调中承载的事情越来越多,面向过程的思想就体现的越来越明显。在实际编程的过程当中,我偏向于同时具备面向对象和面向过程两种思维方式,而不是简单粗暴的认为:面向对象高雅,面向过程低俗。它们的本质是相同的,褪去多态的光环,面向对象只是一种将函数分门别类存放的一种建议。

如何解决回调过于臃肿的问题?

优先考虑将这个回调的事件细分。典型的就是AbsListView类的onTouchEvent,onTouchEvent里面的逻辑非常复杂,为了避免堆积在一起过于凌乱,onTouchEvent被分解成了onTouchDown,onTouchMove,onTouchUp以及onTouchCancel。这样一大块代码就会被打散,交给更细致的回调来分担。


将onTouchEvent细分

如果某个事件的回调中执行的业务逻辑,并不是一类(比如发送网络请求刷新了一下ListView和读取了一下配置文件),不像onTouchEvent这样可以细分,那么问题就会变得比较麻烦,因为我们用事件的回调来解决问题的时候,我们真正想要的是回调函数执行的时机,比如onResume就在那个特定的时机会被调用,如果你需要的就是这个时机,你就只能老老实实的在这里写代码,别无他法。为了代码简洁,我们能做的就是尽可能的将这个承担了多个职责的回调写的足够简单,最好是没有循环,没有分支,就是几个赤裸裸的函数放在哪里,让人一目了然。


回调只提供了一个处理问题的时机,很难保证单一职责

认识到android软件开发是在各种各样的回调上搭建一切功能,是编写代码的第一步,是未来学习设计模式的基础。


文/吴晨(简书作者)
原文链接:http://www.jianshu.com/p/8182921fea87

编程技巧