MVP+Dragger2+Rxjava2+Retrofit+OKhttp进行开发。

来源:互联网 发布:复杂网络社区发现研究 编辑:程序博客网 时间:2024/06/15 00:42
MVP+Dragger2+Rxjava2+Retrofit+OKhttp框架已经流行很长时间,而且也必将成为未来android开发的趋势,在使用这个框架的过程中踩过很多坑,
所以想把我的经验告诉大家,让大家少踩一点弯路。

首先介绍一下MVC和MVP的概念,不懂的同学可以自行百度: 
MVC: 
  • View:对应于布局文件
  • Model:业务逻辑和实体模型
  • Controllor:对应于Activity
MVP :
  • View 对应于Activity,负责View的绘制以及与用户交互
  • Model 依然是业务逻辑和实体模型
  • Presenter 负责完成View于Model间的交互

MVC与MVP的区别: 
    最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。
    还有一点就是Presenter与View之间的交互是通过接口的(代码中会体现), 也就是说MVP中完成了M层和V层的解耦。

以上参考:http://blog.csdn.net/lmj623565791/article/details/46596109

回到本文来,我将介绍怎么把MVP引入到我们的项目中去,
在Android Studio中引入相关配置 在app的build.gradle中添加如下配置:

////引入Dragger2android {    compileSdkVersion 25    buildToolsVersion "25.0.0"    defaultConfig {        applicationId "vko.cn.myapplication"        minSdkVersion 19        targetSdkVersion 25        versionCode 1        versionName "1.0"        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"        jackOptions {            enabled true        }//        ndk {//            // 设置支持的SO库架构//            abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'//        }    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }    //使用DataBinding    dataBinding {        enabled = true    }    // 使用Java1.8, lamdba    compileOptions {        sourceCompatibility JavaVersion.VERSION_1_8        targetCompatibility JavaVersion.VERSION_1_8    }}dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {        exclude group: 'com.android.support', module: 'support-annotations'    })    compile 'com.android.support:appcompat-v7:26.+'    compile 'com.android.support.constraint:constraint-layout:1.0.2'    testCompile 'junit:junit:4.12'    // Rxjava2 + Retrofit + okHttp    compile 'io.reactivex.rxjava2:rxjava:2.1.1'    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'    compile 'com.squareup.retrofit2:retrofit:2.3.0'    compile 'com.squareup.retrofit2:converter-gson:2.3.0'    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'    compile 'com.squareup.okhttp3:okhttp:3.8.1'    //Dragger2    compile 'com.google.dagger:dagger:2.7'    annotationProcessor 'com.google.dagger:dagger-compiler:2.7'    provided 'javax.annotation:jsr250-api:1.0'    //底部菜单    compile 'com.ashokvarma.android:bottom-navigation-bar:1.3.0'    compile 'com.android.support:design:24.0.0'

 在Module的build.gradle中引入: 
buildscript {    repositories {        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:2.3.0'//        //Dagger2//        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'        //lamdba        classpath 'me.tatarka:gradle-retrolambda:3.2.0'//        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.1-2"//        classpath "org.jetbrains.kotlin:kotlin-android-extensions:1.0.1-2"        // NOTE: Do not place your application dependencies here; they belong        // in the individual module build.gradle files    }}

 然后开始构建项目。 项目结构如下: 

 本文只是一个简单的登陆功能展示。首先,我们来看一下M层,V层,P层的接口:如下

/** * Created by A on 2017/9/4. */public class InterfaceContract {    public interface LoginView extends BaseView {        String getUserName();        String getPassWord();        void loginSuccess();        void loginFail();    }    public interface Presenter<T extends BaseActivity> {        void attachView(T t);        void detachView();    }    public  interface ILoginModule{        void login(String userName , String passWord, InterfaceContract.OnLoginListener listener);    }    /**     * presenter层 的回调     */    public interface OnLoginListener {        void LoginSucess();        void LoginFail();    }}
 
LoginView 用来获取用户账号,密码,登陆成功,失败的相关操作 , 继承自BaseView 然后我们再来看看BaseView:

/** * Created by A on 2017/9/4. */public interface BaseView {    void startProgress();    void stopProgress();}

这是一个公共的显示进度的接口,用来显示,隐藏进度条,本项目的进度条采用自定义,可以再Uti包l中查看,

P层中OnLoginListener接口,是用来处理M层登陆成功,失败的回调,而Persenter接口是所有P层的公共接口,
用来处理正在网络请求时,Activity异常退出的问题。

接口看完了,让我们回到代码中,一起看看BaseAcitiviyt的代码:

public abstract class BaseActivity<T extends BasePresenter> extends AppCompatActivity implements BaseView {    @Inject    public T presenter;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);        //去掉Activity上面的状态栏        getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN , WindowManager.LayoutParams. FLAG_FULLSCREEN);        super.onCreate(savedInstanceState);        initPresenter();        initView();        if (Build.VERSION.SDK_INT >= 21) {            View decorView = getWindow().getDecorView();            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;            decorView.setSystemUiVisibility(option);            getWindow().setStatusBarColor(Color.TRANSPARENT);        }    }    public abstract void initPresenter();    public abstract void initView();    @Override    public void startProgress() {        if (!ProgressDlgUtil.isShowing()){            ProgressDlgUtil.showSuccinctProgress(this,"正在验证中...",2,false,false);        }    }    @Override    public void stopProgress() {        ProgressDlgUtil.dismiss();    }}
很简单,定义一个抽象的方法initPresenter();实现BaseView接口,使用泛型获取Presenter的对象,由实现它的子类做具体实现,相信很好理解,

然后我们再来看看LoginActivity的部分
public class LoginActivity extends BaseActivity<LoginPresenter> implements InterfaceContract.LoginView, View.OnClickListener {    private ActivityLoginBinding binding;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    public void initPresenter() {        //完成依赖        DaggerLoginCompent.builder()                .loginModule(new LoginModule(this))                .build()                .inject(this);    }    @Override    public void initView() {        binding = DataBindingUtil.setContentView(this, R.layout.activity_login);        binding.btLogin.setOnClickListener(this);    }    @Override    protected void onDestroy() {        presenter.detachView();        super.onDestroy();    }    @Override    public String getUserName() {        String name = binding.etUser.getText().toString().trim();        return name;    }    @Override    public String getPassWord() {        String md5PassWord = MD5Utils.md5(binding.etPwd.getText().toString().trim()).toLowerCase();        return md5PassWord;    }    @Override    public void loginSuccess() {        Intent intent = new Intent(this,MainActivity.class);        startActivity(intent);        finish();    }    @Override    public void loginFail() {        Toast.makeText(this,"登陆失败",Toast.LENGTH_LONG).show();    }    @Override    public void onClick(View view) {            presenter.login();    }}

 LoginActivity继承自BaseBactivity 实现了LoginView接口,本项目才用DataBing绑定获取对象(DataBing的绑定可以自行百度,减少FindViewById的操作)。在initPresenter中
通过Dagger2注解,来获取Presenter的对象,因为内容较多,Dagger2的用法,将在下次讲解,本次只介绍MVP的内容如何应用到项目中。可以看到V层获取到presenter
的对象以后,通过点击事件,调用login()方法,这时逻辑就到了P层,然后我们再来看看LoginPresenter的代码:     
public class LoginPresenter extends BasePresenter<LoginActivity> implements InterfaceContract.OnLoginListener{//    private InterfaceContract.LoginView mView;    private LoginModelImple modelImple;    @Inject    public LoginPresenter(InterfaceContract.LoginView mView){        attachView((LoginActivity) mView);        modelImple = new LoginModelImple();    }    public void login(){        mView.startProgress();        String userword = mView.getUserName();        String passWord = mView.getPassWord();        modelImple.login(userword,passWord,this);    }    @Override    public void LoginSucess() {        mView.stopProgress();        mView.loginSuccess();    }    @Override    public void LoginFail() {        mView.stopProgress();        mView.loginFail();    }}
同样很简单,思路也很清晰, 通过构造方法获取V层的对象,然后通过传捡来的这个对象,获取user的账号密码,在构造方法中处理化M层的对象,调用M层login()方法,处理登陆的逻辑就到了M层,我们再来看看M层的逻辑,
public class LoginModelImple implements InterfaceContract.ILoginModule{    public Context context;    @Override    public void login(String userName, String passWord, final InterfaceContract.OnLoginListener listener) {        Observable<BaseEntity<UserInfo>> observable = RetrofitFactory.builder().getService().login(userName,passWord);        observable.compose(RxSchedulers.compose()).subscribe(new BaseObserver<UserInfo>(VKOApplication.getInstance()) {            @Override            protected void onHandleSuccess(UserInfo userInfo) {                LogUtils.d(this,"登陆请求的回调-------");                LogUtils.d(this,"userInfo.getToken() = " + userInfo.getToken());                SPUtils.put(VKOApplication.getInstance(),"user_token",userInfo.getToken());                // 保存用户信息等操作                listener.LoginSucess();            }        });    }}

同样的,M层login方法用来处理登陆请求成功 以及 失败对应的方法,我们可以看到,onHandleSucces方法中,回调了P层的登陆成功的方法(登陆失败已经封装到Obseable中,
有兴趣的可以看看)

然后我们再回到P层中,可以看到到,LgoinSucess()方法中,做了两件事,隐藏进度条,回调V层。 然后交给V层来处理登陆成功和失败的相关操作,

再来看看LoginAcitivity中,登陆成功跳转MainActivity ,失败则提示用户账号或密码错误, 整个登陆的逻辑就完成了。可以发现在这个过程中,我们的思路
非常清晰,整个流程采用接口回调的方式,让代码更整洁清除,同时完成了V层和M层的解耦操作。

V层只负责更新UI  而处理耗时操作的逻辑都放在了M层, P层则是连接M和V的桥梁。 好了MVP运用到项目中就到这,下一章我将给大家介绍,如何结合MVP
使用Retrofit+okhttp等android现在流行的框架。

项目地址 :https://github.com/yy-Kevin/MVP-Dagger-Rxjava2-Retrofit







原创粉丝点击