本文来自于腾讯Bugly公众号(weixinBugly),未经做者赞成,请勿转载,原文地址:https://mp.weixin.qq.com/s/M45DM5Ix7a2fmrsE8VPvxgjava
做者:bizaitanweb
导语:MVP开发模式能够帮助项目结构解耦,但其庞大的方法数增长,较为笨重设计对于手Q项目并不很适合。参考以前Web开发经验,提出以页面结构化的解耦方式组织代码。下面讲讲Lego在Android上一次小小尝试设计模式
MVC太过常见这里不啰嗦。实际应用MVC当中,Activity占据打部分的工做,View和Controller的身份分不清。而MVP则是一种设计模式专门优化Activity / Fragment。缓存
先来看看MVP模式的核心思想:View不直接与Model交互性能优化
MVP 把 Activity 中的 UI 逻辑抽象成 View 接口,把业务逻辑抽象成 Presenter 接口,Model 类仍是原来的 Model微信
在MVP设计模式中,网络
【Mode层】咱们直接忽略ide
【View Interface】首页的View接口,抽离出view和presnter交互的接口。由Activity继承实现(Now.java,QQStoryMainActivity.java)工具
public interface IMyStoryListView { public void setData(MyStorys myStoryList, RecentStory recentStoryList); public void setSegmentData(String key, Object data,boolean needRefreshUi); /** * 更新数据后刷新界面走的回调 * @param success * @param isManualPullRefresh */ public void pullRefreshCompleted(boolean success,boolean isReqCompleted); public void launchNewVideoTakeActivity(boolean autoStart, boolean checkSo, int entranceType,String extra); public void setPlayVideoBtnDisplay(boolean display); public void showStartDownload(); public void showDownloadCompleted(boolean success); public void storyPreLoadCompleted(String category, String uin); public void LoadMoreCompleted(boolean repositoryUpdated, boolean isEnd); public void showEmptyView(boolean display); public void requestDataCompleted(); public void openMyStoryListView(boolean open); }
【View】咱们的Activity实现了View接口,而且实现生命周期组件化
public class QQStoryMainAcitivty extends QQStoryBaseActivity implements IMyStoryListView { protected StoryHomePushYellowBarHandler mStoryHomePushYellowBarHandler = new StoryHomePushYellowBarHandler(); protected MystoryListView mainListView; protected IMyStroyPresenter myStoryListPresenter; @Override protected boolean doOnCreate(Bundle savedInstanceState) { super.doOnCreate(savedInstanceState); mainListView = (MystoryListView) super.findViewById(R.id.qqstory_story_main_listview); //Presenter myStoryListPresenter = new StoryListPresenter(this); myStoryListPresenter.setIView(this); return true; } @Override public void onStartAutoRequestFromNet() { startTitleProgress(); mainListView.pullToRefresh(); mStoryHomePushYellowBarHandler.clearYellowBar(); myStoryListPresenter.requestAllDataFromNet(); } private void startTitleProgress(){ // do more } }
举个例子,用户下拉刷新一下。触发到Activity的onStartAutoRequestFromeNet。View逻辑在Activity。
业务逻辑则由Presnter的requestAllDataFromNet去实现。
【Presenter】具体的View->Model,Mode->View由这里实现,其中View是有View接口抽象,进一步规范化View的逻辑。
必要是能够抽出Presenter接口(其实日迹这里没有必要)
public class StoryListPresnter implements IMyStroyPresenter{ protected IMyStoryListView mIView; protected FeedItem mFeedItem; protected ParallelStepExecutor mRequestNetDataExecutor; @Override public void onCreate(boolean needUpdateFromNet) { // 生命周期的逻辑处理 mFeedItem = new FeedItem(); } @Override public void setIView(IMyStoryListView IView) { // 设置View接口(目前实现的是Activity,但其实由其余Fragment,View实现都是能够的,这就是MVP的好处之一,解耦) mIView = IView; } public boolean requestAllDataFromNet() { mRequestNetDataExecutor.addStep(new GetUserSelfInfoStep(null)) .addStep(new ReportWatchVideoListStep(StoryListPresenter.this)) .addStep(new GetUserGuideInfoStep(StoryListPresenter.this)) .onCompleted(new SimpleStepExector.CompletedHandler() { @Override public void done(FeedItem item) { // 伪代码 mFeedItem = item; // 处理Model层 mIView.openMyStoryListView(mFeedItem); // 根据View接口调用View更新 } }).run(); } }
MVP的优缺点:
优势:
MVP的缺点也是很是明确的:
前面铺垫这么多,终于到我要吹水的时候了。MVC,MVP,还有MVVM等MVX系列的设计模式,都是一种大而全的统一管理。在项目结构中最为关键实际上是:分模块!
看看某宝的首页,顶部搜索栏,banner,导航分类,抢购,特价,底部Tab。这是一个Activity的话,你再怎么MVP,也是须要划分模块,而后分而治之。
一个再大的系统,均可以划分一个个小的模块,分而治之
页面结构化,并非新玩意,是当时作web的一套代码风格。下图是当时作Web总结组件化的一张图。如今看来,也就并无过期
页面被划分问一个个区域的模块,有自身的逻辑和规划。有人说,这不就是一个个组件嘛。而后“页面结构化”并非指组件。
例如上图的tabContainer,imgsContainer,listContainer,每个模块都有本身的渲染模板(xml),请求的数据的CGI(数据源),自身的事件绑定(listener) ,状态机(生命周期),并不仅是一个组件,而是一个个有本身生命力,能本身管理的小页面。
根据页面结构,划分出一个个独立维护模块,这就是页面结构化。
页面结构化(Lego)与组件化的区别
下面就以问答的形式,用日迹评论赞项目实战,来说解Lego好处
Lego本身拉取本身的数据,若是一个页面5,6个模块,就拉5,6分PB协议,谈何性能?
这里带出Lego两个特性:
日迹首页评论赞
public FeedCommentLikeLego(Context context, Activity activity, ViewGroup parentView, HomeFeedItem feedItem, int feedType) { super(context, parentView); mHomeFeedItem = feedItem; mFeedItem = feedItem.mFeedBasicItem; mActivity = activity; mFeedType = feedType; mLikeManager = (LikeManager) SuperManager.getAppManager(SuperManager.LIKE_MANAGER); mParentView = LayoutInflater.from(context).inflate(R.layout.qqstory_feed_commentlike_view, parentView, true); // 页面结构 FeedCommentLego commentLego = new FeedCommentLego(mContext, mParentView, mFeedItem, mFeedType); FeedLikeLego likeLego = FeedLikeLego.createIndexFeedLikeLego(mContext, activity, mParentView, mFeedItem, mFeedType); addLego(LEGO_KEY_COMMENT, commentLego); addLego(LEGO_KEY_LIKE, likeLego); commentLego.feed(mHomeFeedItem.getCommentList()); likeLego.feed(mHomeFeedItem.getLikeEntryList()); boot(); }
从FeedCommentLikeLego的构造方法,咱们得知
日迹710这里就有场景,体验出Lego切换数据源的优点。
【首页】出于性能优化,都会作请求合并。返回多个Feed的视频列表,评论赞列表数据。
commentLego.feed(mHomeFeedItem.getCommentList()); likeLego.feed(mHomeFeedItem.getLikeEntryList());
被喂养数据后,Lego内部的DataProvider将不启动
【详情页】同一Lego,默认状况就会启动资金的DataProvider,会本身拉数据
@Override public LegoDataProvider getDataProvider() { return new FeedLikeDataProvider(this, mIsDetailPage); }
一个Lego类是到底是什么?Lego类之间的纽带?
大部分页面的渲染流程线,以下图
咱们把这些经常使用的网络请求,处理数据,事件绑定,上报,容错处理等一系列逻辑方法,以页面块为单位封装成一个Lego模块。
这样的一个抽象层Lego,咱们能够清晰地看到该页面块,请求的数据是什么,绑定了什么事件,作了什么上报,出错怎么处理。
最后加上生命周期,页面结构化的Lego,已经算是一个完整的功能单元了。
继承LegoBase,有几个核心的方法须要重写:
还有生命周期方法能够重写,但不是必要的。
你阅读/接手一个Lego类,会是件很轻松的事情。一个Lego类,核心方法这几个,其他都是业务逻辑方法。
改事件去该Lego的EventHandler,数据要改去DataProvider,产品要求大V才展现底部尾巴,好,去render方法找。
Lego之间的纽带,有三个:
Lego的核心思想是:页面结构分模块,分而治之。解耦,代码可读性高,底层统一优化
在使用了两个版本以后,感受完成度仍是不够。
可是对比MVP,Lego能体验出轻便,逻辑清晰,方法数量少的优点。
Lego页面结构化的应用其实还在尝试阶段。以上算个人一些我的思考和总结。
更多精彩内容欢迎关注腾讯 Bugly的微信公众帐号:
腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的状况以及解决方案。智能合并功能帮助开发同窗把天天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同窗定位到出问题的代码行,实时上报能够在发布后快速的了解应用的质量状况,适配最新的 iOS, Android 官方操做系统,鹅厂的工程师都在使用,快来加入咱们吧!