# android 上 mvp框架 和 agera关联

2023-11-08 12:20
文章标签 android 框架 关联 mvp agera

本文主要是介绍# android 上 mvp框架 和 agera关联,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

android 上 mvp框架

1. mvp 和 mvc

mvc这个东西大家都非常熟悉了,在android项目中mvp大多的实现是,View层就是我买写的xml中的代码,Controller是我们的activity和fragment,model就是各种用来储存数据的bean。然而在真正开发中界面会随着数据的改变而改变,所以在activity中就会融合了ui的控制代码,又融合了数据的请求。这让activity变的十分臃肿,并且增加了耦合度,所以有人提出了更好的模式来改变这一现状那就是mvp模式。
image
如上图,这个是mvp和mvc流程的对比。mvc模式中的Model和view层都和Controller有联系,这个反应在代码中就是Activity会持有各种的bean,而Activity可以直接对bean进行处理并直接更改ui这些都是通过Activity来进行的,这样必会带来耦合。
而mvp模式就不一样这里view和model是被presenter隔离开的,View层只和Presenter有交互不能对model进行直接的修改,这样大量的逻辑代码就放到了presenter中,ui就真的被单独的隔离了出来。在mvp模式中我们熟悉的Activity 和 fragment只是代表View层,他们中不能含有数据,而且只和Presenter进行交互。Presenter层能调数据层接口对数据进行控制。这样view层和model就是完全解耦的了。而且我们还可以编写测试用的view来模拟用户的操作,从而实现对presenter的单元测试问题(比如大量的点击,批量的操作等问题都可以模拟出来)

2.mvp实践

关于mvp的形态google已经在今年早些时候给出了官方的实例。
这个是google官方mvp框架项目的地址:google官方mvp
google大神们推荐了多种mvp的架构的搭建采用了不同的库而产生了不同的方式。而今天我要将google最新的响应式编程库Agera融入到mvp框架中去。来看代码:
我写了一个获取手机中照片的小程序先看xml很很简单就是一个recyclerview和几个button

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_photo"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.hero.jhon.mvp.photo.photoActivity"><android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"android:layout_height="match_parent"android:id = "@+id/recycler"></android.support.v7.widget.RecyclerView><Button
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:text = "clear"android:id = "@+id/button_clear"/><Button
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/button_clear"android:id = "@+id/button_reload"android:text="reload"/><ProgressBar
        android:layout_width="40dp"android:layout_height="40dp"android:layout_centerInParent="true"android:id = "@+id/load_bar"/></RelativeLayout>

为了实现mvp参照google的框架我先写了这样了个基本的接口
BaseView 和 BasePresenter

public interface BasePresenter  {void subscribe();void unsubscribe();}public interface BaseView {void setPresenter(BasePresenter basePresenter);
}

这俩个接口的写法基本招办google 的demo中mvp-rxjava的样式,这里一个基本的BasePresenter中附带的subscribe()订阅和一个unsubscribe()解除订阅的方法这样写更符号Rxjava和Agera这种响应式编程的用法。
我们来看具体的presenter 和 view 的实现,google的demo和其它mvp框架的区别在于,它将每个有具体功能的Presenter 和
View放在一个Contract中来统一管理,在设计这个photoContract就要考验你对这个设计的把握能力了好的工程师能将你要实现的方法快速的展现在这里。

public interface photoContract {interface  View extends BaseView{void AdapterNotify(ArrayList<PhotoBean> lists);void ClearDate();void ShowLoading();void HideLoading();}interface Presenter extends BasePresenter{void Clear();void reload();}
}

通过这里我们应该能很快的知道我们的view能做些什么,我们的Presenter又能做些什么。比如view中的showlong一看就是要展现processbar的方法,ClearDate()就是清除数据的方法。
好,接下来我们看具体View 和 Presenter的实现方式,首先是View就是我们的Activity。

public class photoActivity extends AppCompatActivity implements photoContract.View,View.OnClickListener {private RecyclerView mRecycler;private photoContract.Presenter mPhotoPresenter;private RecyclerAdapter mAdapter;private GridLayoutManager mManager;private Button mButtonClear;private ProgressBar mBar;private Button mButtonReload;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_photo);mRecycler = (RecyclerView)findViewById(R.id.recycler);mManager = new GridLayoutManager(this,4);mRecycler.setLayoutManager(mManager);mAdapter = new RecyclerAdapter(this);mRecycler.setAdapter(mAdapter);mButtonClear = (Button)findViewById(R.id.button_clear);mButtonClear.setOnClickListener(this);mButtonReload = (Button)findViewById(R.id.button_reload);mButtonReload.setOnClickListener(this);mBar = (ProgressBar)findViewById(R.id.load_bar);mPhotoPresenter = new PhotoPresenter(this);}@Overridepublic void setPresenter(BasePresenter basePresenter) {mPhotoPresenter = (photoContract.Presenter)basePresenter;}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.button_clear:mPhotoPresenter.Clear();break;case R.id.button_reload:mPhotoPresenter.reload();break;}}@Overrideprotected void onPause() {super.onPause();mPhotoPresenter.unsubscribe();}@Overrideprotected void onResume() {super.onResume();mPhotoPresenter.subscribe();}@Overridepublic void AdapterNotify(ArrayList<PhotoBean> lists) {mAdapter.setPhotoLists(lists);mAdapter.notifyDataSetChanged();}@Overridepublic void ClearDate() {ArrayList<PhotoBean> lists = new ArrayList<>();mAdapter.setPhotoLists(lists);mAdapter.notifyDataSetChanged();}@Overridepublic void ShowLoading() {mBar.setVisibility(View.VISIBLE);mRecycler.setVisibility(View.GONE);}@Overridepublic void HideLoading() {mBar.setVisibility(View.GONE);mRecycler.setVisibility(View.VISIBLE);}
}

这里可以看到在view层(就是我们的Activity)我们只是负责ui的控制和调用Presenter中的方法并没有获得任何的数据甚至没有定义关于数据的任何变量,这样就可以做到完美的数据和ui的隔离,当ui不变数据改变的时候我们不需要对Activity做出任何的修改。
我们的Presenter是在onResume和onPause中调用了注册和解注册的方法。那数据是怎么获得,逻辑是怎么实现得来看看Presenter

public class PhotoPresenter extends BaseObservable implements photoContract.Presenter,Updatable,Receiver<ArrayList<PhotoBean>> {private photoContract.View mView;private Repository<Result<ArrayList<PhotoBean>>> mRepository;private Executor executor = Executors.newSingleThreadExecutor();public PhotoPresenter(photoContract.View view){mView = view;}@Overridepublic void Clear() {mView.ClearDate();}@Overridepublic void subscribe() {Supplier<Result<ArrayList<PhotoBean>>> supplier = PhotoRepository.getInstance().getDateSupplier();mRepository = Repositories.repositoryWithInitialValue(Result.<ArrayList<PhotoBean>>absent()).observe(this).onUpdatesPerLoop().goTo(executor).thenGetFrom(supplier).compile();mView.ShowLoading();mRepository.addUpdatable(this);}@Overridepublic void update() {mRepository.get().ifSucceededSendTo(this);}@Overridepublic void unsubscribe() {mRepository.removeUpdatable(this);}@Overridepublic void reload() {dispatchUpdate();}@Overridepublic void accept(@NonNull ArrayList<PhotoBean> value) {mView.HideLoading();mView.AdapterNotify(mRepository.get().get());}
}

为了能使用Agera框架我们得Presenter要继承BaseObservable 来表示它是一个被观察者然后又实现了photoContract.Presenter,Updatable,Receiver接口来表明它是一个presenter 并有观察者的特性。这里有大家可能要糊涂了为什么自己要来观察自己呢。很简单我们要保证逻辑的统一性我们只要关系数据的获取和获取数据的操作,而其中一切的生命周期都交给Agera来处理,我们只甚至数据源和订阅数据源。这些我会在Agera中具体讲解。我们只需要知道通过设置数据源和订阅我们能得到我们要的数据在合适的时机。通过agera框架我们能在accept中得到我们要的数据。在这里我们调用了view的AdapterNotify(mRepository.get().get())方法来让activity来实现ui的展示。
那在subscribe 和 unsubscribe中我们做了些什么呢?在subscribe我们创建了一个数据仓库并绑定了我们的presenter做为被观察者和观察者。数据仓库主要是进行数据的获取和处理的,这里我们的数据源是我已经封装好的单例类(这个类从
ContentResolver得到我们想要的照片的数据)它返回一个Supplier做为Agera的数据源。当数据请求完毕观察者会得到通知调用 update() 方法。
下面把PhotoRepository的数据获取贴出

public class PhotoRepository implements GetDate <ArrayList<PhotoBean>> {private Executor executor = Executors.newSingleThreadExecutor();public ContentResolver mContentResolver;Repository<Result<ArrayList<PhotoBean>>> repository;private PhotoRepository() {mContentResolver = BaseApplication.getContext().getContentResolver();}public static PhotoRepository getInstance() {return SingleInstance.repository;}private static class SingleInstance {private static PhotoRepository repository = new PhotoRepository();}@Overridepublic Supplier<Result<ArrayList<PhotoBean>>> getDateSupplier() {return new Supplier<Result<ArrayList<PhotoBean>>>() {@NonNull@Overridepublic Result<ArrayList<PhotoBean>> get() {if (Looper.myLooper() == Looper.getMainLooper()) {Log.d("ddd", "这是主线程");}ArrayList<PhotoBean> list = new ArrayList<PhotoBean>();Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;String[] select = new String[]{MediaStore.Images.Media.DATA,MediaStore.Images.Media.DATE_ADDED,MediaStore.Images.Media.TITLE};Cursor cursor = mContentResolver.query(uri, select, null, null, null);try {if (cursor != null) {int titlenum = cursor.getColumnIndex(MediaStore.Images.Media.TITLE);int datanum = cursor.getColumnIndex(MediaStore.Images.Media.DATA);int timenum = cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED);for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {String title = cursor.getString(titlenum);String date = cursor.getString(datanum);long time = cursor.getLong(timenum);PhotoBean bean = new PhotoBean(title, date, time);list.add(bean);}}} catch (Exception e) {} finally {if (cursor != null) {cursor.close();}}return Result.present(list);}};}

我们使用mvp的优势相对mvc来说,逻辑代码被放到了presenter中model和view层完全解耦。而对于逻辑代码的处理通过使用Agera框架让我们从复杂的线程和生命周期的控制中解放出来。mvp更适合单元测试,更加条理清晰。
当然mvp的缺点也是很明显的为了实现分离要写很多接口相关的代码,我们的学习成本会有所增加。
github地址:超级链接

这篇关于# android 上 mvp框架 和 agera关联的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/369807

相关文章

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求

2025最新版Android Studio安装及组件配置教程(SDK、JDK、Gradle)

《2025最新版AndroidStudio安装及组件配置教程(SDK、JDK、Gradle)》:本文主要介绍2025最新版AndroidStudio安装及组件配置(SDK、JDK、Gradle... 目录原生 android 简介Android Studio必备组件一、Android Studio安装二、A

Java 缓存框架 Caffeine 应用场景解析

《Java缓存框架Caffeine应用场景解析》文章介绍Caffeine作为高性能Java本地缓存框架,基于W-TinyLFU算法,支持异步加载、灵活过期策略、内存安全机制及统计监控,重点解析其... 目录一、Caffeine 简介1. 框架概述1.1 Caffeine的核心优势二、Caffeine 基础2

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

解决若依微服务框架启动报错的问题

《解决若依微服务框架启动报错的问题》Invalidboundstatement错误通常由MyBatis映射文件未正确加载或Nacos配置未读取导致,需检查XML的namespace与方法ID是否匹配,... 目录ruoyi-system模块报错报错详情nacos文件目录总结ruoyi-systnGLNYpe

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.