Android MVP架构项目搭建封装,基类封装

  1. 综述
    对于MVP (Model View Presenter)架构是从著名的MVC(Model View Controller)架构演变而来的。而对于Android应用的开发中本身可视为一种MVC架构。通常在开发中将XML文件视为MVC中的View角色,而将Activity则视为MVC中的Controller角色。不过更多情况下在实际应用开发中Activity不能够完全充当Controller,而是Controller和View的合体。于是Activity既要负责视图的显示,又要负责对业务逻辑的处理。这样在Activity中代码达到上千行,甚至几千行都不足为其,同时这样的Activity也显得臃肿不堪。所以对于MVC架构并不很合适运用于Android的开发中

  2. MVP架构简介
    对于一个应用而言我们需要对它抽象出各个层面,而在MVP架构中它将UI界面和数据进行隔离,所以我们的应用也就分为三个层次。
    - View: 对于View层也是视图层,在View层中只负责对数据的展示,提供友好的界面与用户进行交互。在Android开发中通常将Activity或者Fragment作为View层。
    - Model: 对于Model层也是数据层。它区别于MVC架构中的Model,在这里不仅仅只是数据模型。在MVP架构中Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。
    - Presenter:这一层处理着程序各种逻辑的分发,收到View层UI上的反馈命令、定时命令、系统命令等指令后分发处理逻辑交由Model层做具体的业务操作。
    业务图

  3. 封装应用

    在我们初次搭建项目的时候,我们需要一个高扩展的架构,要学会未雨绸缪。在使用MVP架构的时候我们要考虑到如何将View层与Pesenter层进行连接,如何将Model层与Presenter进行连接
    首先我们需要一个较好的Base基类
    
    BaseView这个baseView没有做太多的处理,你可以添加一些属于你自己的公共业务逻辑
    public interface BaseView<T> {
        //显示进度框
        void showDialog();
    
        //隐藏进度框
        void dismissDialog();
    }
    BasePresent我们这里每次将我们的View层作为泛型传入到我们的Presenter层中,并且作为弱引用将其持有,定义初始化数据的方法,并且做绑定和解绑处理,定义一个抽象的销毁方法
    
       public abstract class BasePresent<T> {
    
        /**
         * 持有UI接口的弱引用
         */
        protected WeakReference<T> mViewRef;
    
        /**
         * 获取数据方法
         */
        public abstract void fetch();
    
        /**
         * 绑定的方法
         * 在onCreate()中调用
         *
         * @param view
         */
        public void attachView(T view) {
            mViewRef = new WeakReference<T>(view);
        }
    
        /**
         * 解绑
         * 在onDestroy方法中调用,防止内存泄漏
         */
        public void detach() {
            if (mViewRef != null) {
                mViewRef.clear();
                mViewRef = null;
            }
    
            onDestroy();
        }
    
        //释放资源处理
        public abstract void onDestroy();
    
    }
    
    BaseModel在BaseModel中,我没有做太多的处理,如果你这边需要添加一些自己的业务逻辑,可以将baseModel写为抽象类,方便以后的扩展
    
    public interface BaseModel {
    }
    
  4. 实际应用

    直接上代码

public abstract class BaseActivity<V, T extends BasePresent<V>> extends AppCompatActivity {

    /**
     * P层引用
     */
    protected T mPresent;
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //创建Presenter层
        mPresent = createPresent();
        //做绑定
        mPresent.attachView((V) this);

        //P层数据初始化逻辑
        mPresent.fetch();
    }

    /*
     * @params
     * @name 子类实现具体的构建过程
     * @data 2017/11/20 15:39
     * @author :MarkShuai
     */
    protected abstract T createPresent();

     @Override
    protected void onDestroy() {
        mPresent.detach();
        super.onDestroy();
        Log.d(TAG, "onDestroy()");

    }

}

直接将View层与Present作为泛型传入其中,将View层与Presenter层进行了绑定,每次将BasePresenter层中的初始化数据方法进行了调用,并且在各个生命周期中,做了防止内存泄漏等。这里我只是抽出了MVP的代码部分进行了讲解,demo中对BaseActivity进行了不错的封装,对Android 兼容性的沉浸式、6.0动态授权,和公共方法的抽取都进行了封装

下面接着来看代码

public interface SerViceUpLoadContract {
    interface View extends BaseView<SerViceUpLoadContract.Present> {
        void setProgress(Integer progress);
    }

    abstract class Present<T> extends BasePresent<SerViceUpLoadContract.View> {
        //绑定服务
        abstract void bindPresentService();
        //开始更新APK
        abstract void startUpLoadAPK(T t);
    }


    interface Model extends BaseModel {
        //绑定服务
        void bindModelService(Context context);

        //开始下载
        void startUpLoad(Context mContext, ProgressListener listener);

        //观察者的监听接口回调
        interface ProgressListener {

            void onSubscribeProgress(Disposable d);

            void onNextProgress(Integer progress);

            void onErrorProgress(Throwable throwable);

            void onCompleteProgress();
        }
    }
}

每次在我们进行调用的时候我是喜欢写这样的一个接口,因为这样的话后期方便你的管理,你直接从Contract中就看了大概你这个Activity做了些什么事情。


public class SerViceUpLoadModel implements SerViceUpLoadContract.Model {

    private DownloadService.DownloadBinder mDownloadBinder;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mDownloadBinder = (DownloadService.DownloadBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mDownloadBinder = null;
        }
    };

    @Override
    public void bindModelService(Context context) {
        Intent intent = new Intent(context, DownloadService.class);
        context.startService(intent);
        context.bindService(intent, mConnection, BIND_AUTO_CREATE);//绑定服务
    }

    @Override
    public void startUpLoad(Context mContext, ProgressListener listener) {
        File file = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "test.apk");
        boolean isHave = SDCardHelper.fileIsHave(file.getPath());
        if (isHave) {
            ToastUtils.showToast("存在了");
        } else {
            if (mDownloadBinder != null) {
                long downloadId = mDownloadBinder.startDownload(ContentManager.APK_URL);
                startCheckProgress(downloadId, mContext, listener);
            }
        }
    }

    //开始监听进度
    private void startCheckProgress(long downloadId, Context mContext, ProgressListener listener) {
        Observable
                .interval(100, 200, TimeUnit.MILLISECONDS, Schedulers.io())//无限轮询,准备查询进度,在io线程执行
                .filter(time -> mDownloadBinder != null)
                .map(i -> mDownloadBinder.getProgress(downloadId))//获得下载进度
                .takeUntil(progress -> progress >= 100)//返回true就停止了,当进度>=100就是下载完成了
                .distinct()//去重复
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new ProgressObserver(mContext, listener));
    }

    //观察者
    private class ProgressObserver implements Observer<Integer> {
        private Context mContext;
        private ProgressListener listener;

        public ProgressObserver(Context mContext, ProgressListener listener) {
            this.mContext = mContext;
            this.listener = listener;
        }

        @Override
        public void onSubscribe(Disposable d) {
            listener.onSubscribeProgress(d);
        }

        @Override
        public void onNext(Integer progress) {
            listener.onNextProgress(progress);
        }

        @Override
        public void onError(Throwable throwable) {
            listener.onErrorProgress(throwable);

        }

        @Override
        public void onComplete() {
            listener.onCompleteProgress();

        }
    }


}

这个是Mdoel层的使用

接下来继续看代码

public class SerViceUpLoadPresent<T> extends 
                                SerViceUpLoadContract.Present<SerViceUpLoadContract.View> {

    private Context mContext;
    private SerViceUpLoadContract.Model mModel;
    private Disposable mDisposable;//可以取消观察者


    public SerViceUpLoadPresent(Context mContext) {
        this.mContext = mContext;
        mModel = new SerViceUpLoadModel();
    }

    @Override
    public void fetch() {

    }

    @Override
    void bindPresentService() {
        mModel.bindModelService(mContext);
    }

    @Override
    void startUpLoadAPK(SerViceUpLoadContract.View view) {
        mModel.startUpLoad(mContext, new SerViceUpLoadContract.Model.ProgressListener() {
            @Override
            public void onSubscribeProgress(Disposable d) {
                mDisposable = d;
            }

            @Override
            public void onNextProgress(Integer progress) {
                view.setProgress(progress);
            }

            @Override
            public void onErrorProgress(Throwable throwable) {
                throwable.printStackTrace();
                ToastUtils.showToast("出错了");
            }

            @Override
            public void onCompleteProgress() {
                view.setProgress(100);
                ToastUtils.showToast("下载完成");
            }
        });

    }


    @Override
    public void onDestroy() {
        if (mDisposable != null) {
            //取消监听
            mDisposable.dispose();
        }
    }

}

我们的Present层没有进行去 new 一个View 层,仅仅是将我们的泛型坐入其中,让其使用

接下来是我们的View层

public class SerViceUpLoadActivity extends BaseActivity<SerViceUpLoadContract.View, SerViceUpLoadPresent<SerViceUpLoadContract.View>> implements SerViceUpLoadContract.View {


    @BindView(R.id.bt_upload)
    Button mButtonUpLoad;
    @BindView(R.id.down_progress)
    ProgressBar mDownLoadProgress;

    @Override
    public View bindView() {
        return null;
    }

    @Override
    public int bindLayout() {
        return R.layout.activity_ser_vice_up_load;
    }

    @Override
    public void initView(View view) {
        //绑定下载服务
        mPresent.bindPresentService();
    }

    @Override
    public void initDataAfter() {

    }

    @Override
    public void setListener() {
        mButtonUpLoad.setOnClickListener(this);
    }

    @Override
    public void widgetClick(View v) {
        switch (v.getId()) {
            case R.id.bt_upload:
                mPresent.startUpLoadAPK(this);
                break;
        }
    }

    @Override
    protected SerViceUpLoadPresent<SerViceUpLoadContract.View> createPresent() {
        return new SerViceUpLoadPresent<>(this);
    }

    @Override
    public void showDialog() {
        LoadingDialog.show(mContext);
    }

    @Override
    public void dismissDialog() {
        LoadingDialog.dismiss(mContext);
    }

    @Override
    public void setProgress(Integer progress) {
        mDownLoadProgress.setProgress(progress);
    }
}

在我们的View层中我们主要是刷新UI来使用的。
这就是我今天带来的我理解封装MVP,有不足的地方欢迎大家指正批评。

源码地址:https://github.com/MarkMingShuai/AndroidMVPObject
喜欢的话请点个赞,给个start

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
封装Selenium基类是一种常见的测试框架设计模式,它可以提供一些通用的方法和属性,以便在测试过程中更方便地使用Selenium库。下面是一个简单的封装Selenium基类的示例: ```python from selenium import webdriver class BasePage: def __init__(self, driver): self.driver = driver def open_url(self, url): self.driver.get(url) def find_element(self, locator): return self.driver.find_element(*locator) def click(self, locator): element = self.find_element(locator) element.click() def input_text(self, locator, text): element = self.find_element(locator) element.clear() element.send_keys(text) # 其他通用方法... ``` 在这个示例中,`BasePage`接受一个`driver`参数,该参数是一个已经初始化好的Selenium WebDriver对象。`BasePage`提供了一些常用的方法,如`open_url`用于打开指定的URL,`find_element`用于查找页面元素,`click`用于点击元素,`input_text`用于输入文本等。 通过封装Selenium基类,你可以在具体的测试页面中继承`BasePage`,并直接使用其中定义的方法,从而简化测试代码的编写。例如: ```python class LoginPage(BasePage): def __init__(self, driver): super().__init__(driver) self.username_locator = (By.ID, 'username') self.password_locator = (By.ID, 'password') self.login_button_locator = (By.ID, 'login-button') def login(self, username, password): self.input_text(self.username_locator, username) self.input_text(self.password_locator, password) self.click(self.login_button_locator) # 其他页面特定方法... ``` 在`LoginPage`中,我们继承了`BasePage`,并定义了一些页面特定的元素定位器和方法,同时可以直接使用`BasePage`中定义的通用方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值