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

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层的解耦。


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

引入Dragger2
android {
    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







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值