天天看點

Android RxJava+Retrofit2.0+MVP的小試牛刀

這篇文章主要介紹Android Rxjava和Retrofit在MVP設計模式中的使用

Rxjava封裝了異步操作,不用再寫煩人的Handler,AsyncTask 讓代碼更簡潔,邏輯更清晰,程式邏輯越複雜,Rxjava更能展現作用。

Retrofit是一個封裝了網絡操作的開源庫

MVP設計模式就是使程式各個子產品各司其職,互不幹擾

View層專門負責與使用者互動,邏輯處理不用管

Model層專門負責邏輯處理,你來個蘿蔔我就給你做成蘿蔔幹,來個白菜就給你做成南韓泡菜

Presenter主要負責連接配接Model和View的,我的了解就是搬運工,Presenter把View(Activity)送過來的蘿蔔給Model,Model做好的蘿蔔幹通過Presenter傳回給View

道理很簡單,都會說,但是真要實作起來還是有一定難得的,MVP難得就是一個思想,接口的定義,方法的回調都是比較抽象的,這需要不斷地學習,多寫多看。

在這裡我就不單獨介紹Rxjava和Retrofit這兩個開源庫了,網上有大把的部落格

想學Rxjava的同學可以從這進入http://gank.io/post/560e15be2dca930e00da1083

想學Retrofit的同學請看這http://square.github.io/retrofit/

下面正式開始介紹如何使用RxJava+Retrofit2.0+MVP實作一個網絡請求

首先,把需要用到的開源庫在build.gradle中搞下來,這個例子中會用到

retrofit,Rxjava,okhttp,RxAndroid,Gson,SmartRefreshLayout,glide這些開源庫

compile 'com.android.support:appcompat-v7:25.3.1'

compile 'com.android.support:recyclerview-v7:23.4.0'

compile 'com.squareup.retrofit2:retrofit:2.3.0' 

compile 'com.squareup.retrofit2:converter-gson:2.0.2'

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
           
compile 'com.squareup.okhttp3:okhttp:3.3.1' 網絡請求的,retrofit主要是封裝了請求操作,網絡擷取資料還是靠okhttp

compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.0.3'

compile 'io.reactivex:rxandroid:1.1.0'

compile 'com.github.bumptech.glide:glide:4.0.0'
           

需要的開源庫都準備好了,接下來可以開始幹活了。既然用到了mvp設計模式,那樣就不能像平時那樣上來就開始在activity中寫代碼了,先得把架構打起來,然後再慢慢填充内容,就像建房子一樣,一步一步來。先把包建好,這個自由發揮,沒有固定的模式,看起來一目了然就行了,别後期找個類都要找半天,不曉得在哪個包裡面,還得一個一個的看

Android RxJava+Retrofit2.0+MVP的小試牛刀

包建好了,下面就開始設計了,代碼不着急。

首先,要知道我們要幹什麼,需要實作什麼樣的功能,用什麼實作。

我們要通路網絡,從網上加載資料,顯示到街面上,使用mvp模式用一些開源庫實作

好了,知道要幹什麼,知道了用什麼方法實作,接下來就好弄了,很多時候,難就難在我們不曉得要幹什麼

擷取資料,這麼複雜的操作不能再activity中實作,本來人家和使用者互動就夠煩了,還把這麼麻煩的事都交給他去做,後面可能會出事,咋們交給model去做,但是交給model做了,怎麼把擷取到的資料交給view了,這就需要我們設計好接口,通過回調的方式将資料傳回給persenter,在通過persenter傳遞給View,實作了model層和view盡可能的解耦

Model

先定義兩個IModle 的接口

package modle.Impl;

import java.util.List;

import bean.Book;

/**
 * Created by Administrator on 2017/9/7.
 */

public interface IBookModle extends IModle{
    void getBook(AsyncCallback callback,String name,int start,int count);
}
           
package modle.Impl;

/**
 * Created by limeng on 2017/9/7.
 */

public interface IModle {
     public interface AsyncCallback {

        void onSuccess(Object success);

        void onError(Object error);
    }
}
           

既然是擷取資料,就需要有個擷取資料的方法,通過getBook方法來擷取資料,AsyncCallback 這個參數是等下回調的時候會傳遞過來的的參數,name書本的名字,start是從那條資料開始,count是擷取多少條資料

package modle;

import android.util.Log;

import com.google.gson.Gson;


import bean.Book;
import impl.ApiService;
import modle.Impl.IBookModle;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;

/**
 * Created by limeng on 2017/9/7.
 */

public class BookModle implements IBookModle {
    private Retrofit mRetrofit;
    private ApiService request;
    @Override
    public void getBook(final AsyncCallback callback, String name, int start, int count) {
        mRetrofit = new Retrofit.Builder()
                .baseUrl("https://api.douban.com/v2/") // 設定
                .addConverterFactory(GsonConverterFactory.create(new Gson())) // 設定使用Gson解析(記得加入依賴)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        // 步驟5:建立 網絡請求接口 的執行個體
        request = mRetrofit.create(ApiService.class);
        // 對 發送請求 進行封裝
        request.getCall(name, null, start, count)
                .subscribeOn(Schedulers.newThread())
                .doOnNext(new Action1<Book>() {
                    @Override
                    public void call(Book bean) {
                        Log.e("limeng", "doOnNext" + Thread.currentThread().getName());
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Book>() {
                    @Override
                    public void call(Book book) {
                        callback.onSuccess(book);
                    }

                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        callback.onError(throwable);
                    }
                });
    }
}
           

定義一個modelBook類實作IModelBook,重寫他的getBook方法,然後擷取資料,當請求成功時,通過persenter傳遞過來的callback回調callback.onSuccess(book);這樣persenter就擷取到了資料,請求失敗時callback.onError(throwable);

persenter

同樣是先定義接口

package presenter;

/**
 * Created by Administrator on 2017/9/6.
 */

public interface IBookPresenter {
    void loadBook(String name,int start,int count);
}
           

這個用來加載資料,其實方法名應該跟model換下的,model才是加載資料,persenter才是get資料

package presenter.Impl;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import java.util.List;

import bean.Book;
import modle.BookModle;
import modle.Impl.IBookModle;
import modle.Impl.IModle;
import presenter.IBookPresenter;
import view.IBookView;

/**
 * Created by limeng on 2017/9/6.
 */

public class BookPresenter implements IBookPresenter{
    private IBookModle modle;
    private IBookView mBookView;
    public BookPresenter(IBookView view){
        mBookView=view;
        modle=new BookModle();
    }
    @Override
    public void loadBook(String name,int start,int count) {
        modle.getBook(new IModle.AsyncCallback() {
            @Override
            public void onSuccess(Object success) {
                Book book= (Book) success;
                mBookView.upDataBookList(book);
            }
            @Override
            public void onError(Object error) {
                Throwable throwable= (Throwable) error;
                Log.e("limeng","throwable="+throwable.toString());
                Toast.makeText((Context) mBookView,"加載資料失敗",Toast.LENGTH_LONG).show();
            }
        },name,start,count);
    }
}
           

建立一個BookPresenter類實作接口,重寫loadBook方法,弄一個構造函授,用來接收view,建立一個model的執行個體,再在loadBook方法中調用model的getBook方法,new一個AsyncCallback對象,重寫他的

onSuccess(),            
onError()方法,這樣就擷取到了傳回的資料,同時還要傳遞書名name,start,count,這三個參數就是你想要擷取到什麼樣的資料

           

View

沒得說,先定義接口

           
package view;

import java.util.List;

import bean.Book;

/**
 * Created by Administrator on 2017/9/7.
 */

public interface IBookView {
    void upDataBookList(Book book);
}
           
定義一個IBookView的接口,裡面的upDataBookList主要是通過擷取到的資料更新界面的
package com.limeng.ke.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnLoadmoreListener;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;

import java.util.List;

import adapter.RecyAdapter;
import bean.Book;
import fragment.MyFragment;
import presenter.IBookPresenter;
import presenter.Impl.BookPresenter;
import view.IBookView;


public class MainActivity extends Activity implements View.OnClickListener, MyFragment.LogLinsenter, IBookView {
    private Button btnLoadData;//點選加載資料
    private Button btnDelete;//删除資料
    private Button btnAdd;//添加資料

    private RefreshLayout mRefreshLayout;
    private RecyclerView mRecyclerView;
    private SmartRefreshLayout smartRefreshLayout;
    private RecyAdapter mAdapter = null;

    private Book book = null;
    private IBookPresenter mPresenter;
    private List<Book.BooksBean> mBoosBeanList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//      initData();
        initView();
        mPresenter = new BookPresenter(MainActivity.this);
        initData();
        initAdapter();
    }

    private void initData() {

    }

    private void initAdapter() {

    }

    private void initView() {
//        mRefreshLayout = (RefreshLayout) findViewById(R.id.refreshLayout);
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        mRefreshLayout = (RefreshLayout) findViewById(R.id.smartRefreshLayout);
        btnLoadData = (Button) findViewById(R.id.iv_Pic1);
        btnDelete = (Button) findViewById(R.id.btn_delete);
        btnAdd = (Button) findViewById(R.id.btn_add);
        btnLoadData.setOnClickListener(this);
        btnDelete.setOnClickListener(this);
        btnAdd.setOnClickListener(this);
//        Glide.with(MainActivity.this).load(Images.imageUrls[0]).into(ivPic1);
        mRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
            @Override
            public void onRefresh(RefreshLayout refreshlayout) {
                int start = book.getStart();
                int count = book.getCount();
                //向下拉重新整理
                Log.e("limeng", "正在重新整理--------->start=" + start);
                Log.e("limeng", "正在重新整理--------->count=" + count);
                refreshlayout.finishRefresh(5000);
            }

        });
        mRefreshLayout.setOnLoadmoreListener(new OnLoadmoreListener() {
            @Override
            public void onLoadmore(RefreshLayout refreshlayout) {
                //向上拉加載更多
                refreshlayout.finishLoadmore(5000);
            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_Pic1:
                mPresenter.loadBook("金瓶梅", 0, 10);
                break;
            case R.id.btn_add:
                mAdapter.addData(1);
                break;
            case R.id.btn_delete:
                mAdapter.removeData(1);
                break;
        }
    }

    @Override
    public void log(String name) {
    }

    @Override
    public void upDataBookList(Book book) {
        Log.e("limeng", "upDataBookList");
        this.book=book;
        mBoosBeanList = book.getBooks();
        RecyAdapter adapter = new RecyAdapter(MainActivity.this, mBoosBeanList);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));//這裡用線性顯示 類似于listview
        mRecyclerView.setAdapter(adapter);
    }
}
           
activity實作IBookView接口,重寫unDataBookList方法,執行個體化一個presenter對象,使用者通過點選事件,想要擷取資料,點選按鈕,通過presenter對象調用 mPresenter.loadBook("金瓶梅", 0, 10);這個方法,然後會觸發presenter中的model執行個體調用getBook方法,然後在觸發model中的getBook方法擷取資料,通過 AsyncCallback這個接口中的onSuccess(),onError()兩個方法将資料回調給presenter,在presenter中通過IBookview接口中的 mBookView.upDataBookList(book);方法将資料回調給activity,最後activity重寫upDataBookList(book)方法擷取資料 最終實作了view發送指令,通過presenter交給model,model處理完邏輯,将資料通過presenter傳回給activity,邏輯資料層與View的完美解耦,這樣是代碼更清晰,閱讀起來更加容易,也利于代碼的後期維護
最後附上demo代碼http://download.csdn.net/download/u010471406/9970769