Android开发-浅谈架构(一)

写在前面的话

嗯 聊聊架构。 这段时间一直在维护旧项目。 包括自己之前写的新项目 越来越发现 一个架构清晰的项目往往让人赏心悦目。不至于在一个bug丢过来之后手足无措。包括以后别人接收自己的项目 能很快上手 何乐而不为呢?

曾经的"MVC"

先从我们曾经的 "MVC" 说起, "MVC" 全名 "Model View Controller".即 视图层(View), 控制层(Controller),模型层(Model).他们之间的关系 如图:


MVC

视图层(View) 一般由 xml布局文件担任 控制层(Controller) 一般由 activity和fragment 担任 模型层 (Model) 一般指的是 抽离出来的接口扩展。 尝尝可以复用的那一部分。 你只需要把接口 在Controller 抛出。 更新 View即可。其实我们刚开始参与项目开发 技术薄弱的时候 都会想到把复用的部分抽离出来 但是activity类写的很臃肿 至少不够优雅这其实就是MVC

写到这里 我们知道android中 Controller 控制层一般有Activity(主要)和fragment 担任。但是activity类中 常常包含一些ui 初始化 或者 网络 第三方sdk 的初始化又或者是业务逻辑。那么 这样写起代码层就会变得臃肿。而且不够优雅。那么MVP就从MVC中眼花诞生了。


MVP

MVP中的model层继续沿用MVC中的model

大家看这个图 也许不是很清楚或者说不是太理解。
在这里 "View" 由presenter中的接口担任 实现向View实现类通信,你也可以在Android组件中实现它。有时最好直接使用Activity,Fragment或自定义View。>The view that receives commands from a presenter in MVP, is referred to as "view"

先说Model: 它是一个负责管理数据的接口。模型的职责包括使用API、缓存数据、管理数据库等。该模型也可以是一个接口,与其他模块负责这些职责的沟通。例如,如果您使用的是存储库模式,则该模型可能是一个存储库。如果您使用的是干净的建筑,相反,该模型可以关联。(翻译过来略显生硬 简而言之 Model层是数据访问层,如数据库API或远程服务器API)

Presenter:大家可以看到Model和View是完全没有交互的。那么 Presenter则担当Model与View之间的中间人。你所有的业务逻辑都属于它。Presenter负责查询模型和更新视图,响应用户交互更新模型。

View:The view can be implemented by Activities, Fragments, any Android widget or anything that can do operations like showing a ProgressBar, updating a TextView, populating a RecyclerView and so on.(这个翻译起来有点尴尬 感觉大家应该都能看懂)

对照MVC图来看 我们发现 View 中出现了<Interface> 而Presenter中也出现了<Interface> .什么意思呢? 我们看Presenter中的代码实例:

View中的TicTacToeView示例

关于

  1. 怎么写Model
  2. 如何理解View
  3. 如何写Presenter
    参考 MVP详解

关于MVP文字性的描述就这么多。其实网上大部分讲解都是套三者之间的关系交互图来讲的。只有理解了尝试敲几遍就差不多会了。另外 符合项目需要的才是最好的。下面我尝试着动手仿照 ONE 一个app将MVP模式套入其中练手(项目会不断完善的 架构 分包开始)

先截个图 看一下目前大致的结构。

aaa.png

没用到Presenter之前切换Fragment MainActivity切换标签页:
<code>

 FragmentUtils fragmentUtil = new FragmentUtils(this, R.id.view_container);
fragmentUtil.switchTo(OneFragment.class);
mBinding.radio.setOnCheckedChangeListener((group, checkedId) -> {
  switch (checkedId) {
    case R.id.home_one:
      fragmentUtil.switchTo(OneFragment.class);
      break;
    case R.id.home_reading:
      fragmentUtil.switchTo(ReadingFragment.class);
      break;
    case R.id.home_music:
      fragmentUtil.switchTo(MusicFragment.class);
      break;
    case R.id.home_movie:
      fragmentUtil.switchTo(MovieFragment.class);
      break;
    default:
      break;
  }
});

</code>
用到Presenter之后:

<code>
if(presenter==null)
presenter = new MainTabPresenter(this, mBinding.radio);
presenter.switchTo();
</code>

其中 HomeActivity 类:
<code>
public class HomeActivity extends BaseActivity<HomeActBinding> {
private MainTabPresenter presenter;
@Override
protected int getLayoutId() {
return R.layout.home_act;
}
@Override
protected void setupView() {
if(presenter==null)
presenter = new MainTabPresenter(this, mBinding.radio);
presenter.switchTo();
}
}
</code>

BaseActivity类:
<code>
public abstract class BaseActivity<T extends ViewDataBinding> extends AppCompatActivity{
protected T mBinding;
protected ApiInteractor api;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initLayout();
}
private void initLayout() {
AppComponent appComponent = ((App) getApplication()).getAppComponent();
api = appComponent.getApiInteractor();
ViewDataBinding inflate = DataBindingUtil.setContentView(this, getLayoutId());
mBinding = DataBindingUtil.bind(inflate.getRoot());
if (mBinding == null) {
if (getLayoutId() == 0) {
throw new InflateException("activity no source_ID");
} else {
throw new NullPointerException("mBinding==NULL");
}
}
setupView();
}
@LayoutRes
protected abstract int getLayoutId();
protected abstract void setupView();
}
</code>

Presenter类:
<code>
public class MainTabPresenter implements MainTabContract.Presenter {
private RadioGroup radioGroup;
private final FragmentActivity mContext;
public MainTabPresenter(@Nullable FragmentActivity mActivity, @Nullable RadioGroup group){
mContext = checkNotNull(mActivity, "FragmentActivity cannot be null!");
radioGroup = checkNotNull(group, "RadioGroup cannot be null!");
}
@Override
public void switchTo() {
FragmentUtils fragmentUtil = new FragmentUtils(mContext, R.id.view_container);
fragmentUtil.switchTo(OneFragment.class);
radioGroup.setOnCheckedChangeListener((group1, checkedId) -> {
switch (checkedId) {
case R.id.home_one:
fragmentUtil.switchTo(OneFragment.class);
break;
case R.id.home_reading:
fragmentUtil.switchTo(ReadingFragment.class);
break;
case R.id.home_music:
fragmentUtil.switchTo(MusicFragment.class);
break;
case R.id.home_movie:
fragmentUtil.switchTo(MovieFragment.class);
break;
default:
break;
}
});
}
@Override
public void start() {//有些地方 RxJava MediaPlayer Handler 等生命周期用得上
}
}
</code>
简单的逻辑代码交由Presenter 和Model协作实现。可能表述 和理解的不是太好 欢迎指正。Demo架构Dagger2+RxJava+Retrofit 雏形已经大致出现 后面会陆续补充一些使用的小技巧 和 第三方的插入 譬如 微信热修复 等等吧。谢谢大家~

github demo地址

参考:
MVC vs. MVP vs. MVVM on Android
Android App的设计架构:MVC,MVP,MVVM与架构经验谈
官方MVP Dagger2

等等 分享几个免费的api(侵删 谢谢)
干货Api
和风天气
one 抓包接口

欢迎加群:
QQ 群 521039620
原文博客地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,501评论 25 707
  • 转载至:http://www.jianshu.com/p/9a6845b26856 “Android MVP 详解...
    SnowDragonYY阅读 10,319评论 5 241
  • 作者:李旺成 时间:2016年4月3日 “Android MVP 详解(下)”已经发布,欢迎大家提建议。 MVP ...
    diygreen阅读 128,816评论 86 1,321
  • 第一次月考来了,以前都是我坐在下面,别人看着我,第一次我坐在上面,我看着别人。突然觉得学生们好傻,自以为在下...
    忘记了丶就不要再想起阅读 169评论 0 0
  • 你有过这样的经历吗?翻看朋友圈都是朋友发的旅行照片,孩子照片,结婚照等,一遍遍看到空间里面自己的朋友动态里面五花八...
    风帆正阳阅读 223评论 0 0