# 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实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

数据治理框架-ISO数据治理标准

引言 "数据治理"并不是一个新的概念,国内外有很多组织专注于数据治理理论和实践的研究。目前国际上,主要的数据治理框架有ISO数据治理标准、GDI数据治理框架、DAMA数据治理管理框架等。 ISO数据治理标准 改标准阐述了数据治理的标准、基本原则和数据治理模型,是一套完整的数据治理方法论。 ISO/IEC 38505标准的数据治理方法论的核心内容如下: 数据治理的目标:促进组织高效、合理地

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使