0.前言
本文是Philm源码分析系列的第二篇,重点分析Philm MVP结构中View与Presenter的设计。为了便于分析,本文选取了Philm中最简单的部分About,这部分用于展示Philm的关于信息,不包含任何Model代码。
1.绑定View和Presenter
在Philm中,View由Fragment和Activity实现,由于应用启动时首先启动Activity,因此,绑定Presenter的工作要在View中进行(也就是Activity/Fragment)。Philm在AboutFragment的onResume方法和onPause方法中进行View与Presenter的绑定与解绑。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class AboutFragment extends ListFragment<ListView> implements AboutController.AboutListUi { ... @Override public void onResume() { super.onResume(); getController().attachUi(this); } @Override public void onPause() { getController().detachUi(this); super.onPause(); } ... } |
对于Philm的About部分,它的Presenter就是MainController中的AboutController(是的,Chris Banes将Presenter命名为了Controller)。
2.设置回调
下面来看Presenter(BaseUiController)中attachUi的实现:
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 29 | abstract class BaseUiController<U extends BaseUiController.Ui<UC>, UC> extends BaseController { public interface Ui<UC> { void setCallbacks(UC callbacks); boolean isModal(); } ... public synchronized final void attachUi(U ui) { Preconditions.checkArgument(ui != null, "ui cannot be null"); Preconditions.checkState(!mUis.contains(ui), "UI is already attached"); mUis.add(ui); ui.setCallbacks(createUiCallbacks(ui)); if (isInited()) { if (!ui.isModal() && !(ui instanceof SubUi)) { updateDisplayTitle(getUiTitle(ui)); } onUiAttached(ui); populateUi(ui); } } ... } |
这里最重要的两处代码是1)通过ui.setCallbacks(createUiCallbacks(ui))设置回调;和2)绘制Ui populateUi(ui)。
Philm在设置View回调是采用了一个非常精巧的设计:通过泛型来处理ViewInterface与回调。BaseUiController的泛型可以表示为BaseUiController<viewinterface, ViewCallbacs>,其中前一个泛型代表了前文所述用于解耦View和Presenter而实现的ViewInterface,而后一个是提供给ViewInterface的回调。ViewInterface本身提供了setCallbacks方法来进行ViewCallbacks与View的绑定。这样,所有的业务逻辑都可以在Presenter中实现,之后通过回调提供给View。View仅仅负责UI的表现,在需要处理业务逻辑时,通过调用之前Presenter设置的回调实现。
这里可以看一下About中响应List中某个item被点击的实现。这里onListItemClick继承自ListFragment,用于响应某个item的点击事件,AboutFragment将这个事件交给了Presenter设置的回调来处理。
1 2 3 4 5 6 7 8 9 10 11 12 | public class AboutFragment extends ListFragment<ListView> implements AboutController.AboutListUi { ... @Override public void onListItemClick(ListView l, View v, int position, long id) { AboutController.AboutItem item = (AboutController.AboutItem) l.getItemAtPosition(position); if (item != null && hasCallbacks()) { getCallbacks().onItemClick(item); } } ... } |
3.Display
这是Philm中一处比较新颖的设计,它本身应该算是Presenter的一部分,具体的实现在AndroidDisplay这个类中。它的作用是负责app中所有UI切换的工作,比如Activity跳转,现实Fragment,弹出Drawer等。听起来很不可以思议,但是由于这些代码都很短小,实际上这个类并不大,也不复杂。