mvp+rxjava2.0+retrofit2.0+realm

本文屬於技術的合併,所以不會對mvp、rxjava等的技術進行初始使用的講解。建議對這些技術有一定基礎後查看。

先看依賴

先在根目錄(工程目錄)build.gradle添加realm的插件安裝

buildscript {  
    repositories {  
        jcenter()  
    }  
    dependencies {  
        classpath "io.realm:realm-gradle-plugin:2.3.0"
    }  

再在app的gradle中添加

android {
    apply plugin: 'realm-android'
}
dependencies {
    implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'

    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合rxjava2
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

    implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'//攔截器
}

1.mvp包分類:

Contact:(1)view接口(2)presenter接口    ----作爲接口統籌調用,以供v層和p層的互相調用。也方便開發者理清邏輯

Activity:繼承view接口持有presenter 的接口--持有接口不持有presenter實例,以保證層與層調用皆以接口調用。

----對應v層


presernter:繼承presenter接口--網絡或數據庫耗時操作時使用rxjava2.0啓動異步

 ----對應P層

 

model: (1)DBhelper--Realm(2)RetrofitService--retrofit2.0

數據庫耗時操作和網絡請求都在p層調用。 

 ----對應M層

2.具體代碼:

以登錄爲例子:

先看Contact:

public interface LoginContact {
    interface view extends BaseView {
        void loginSuccess();
    }

    interface presenter extends BasePresenter {
        /**
         * 登錄
         */
        void login(LoginRequest request);
    }
}

如果熟悉MVP的會發現這裏沒有Model的接口。因爲使用Retrofit的緣故,將網絡請求Model是直接用RetroditService文件來直接調用,而數據庫用的Realm,數據庫存取用DBHelper。即Model層是共用兩種文件:

  1. Retrofit的網絡請求實體類
  2. Realm的數據存取實體類

寫到persenter的實體類請求則會清晰明瞭些。如下:

public class LoginPresenter extends BasePresenterImpl<LoginContact.view>
        implements LoginContact.presenter {

    public LoginPresenter(LoginContact.view view) {
        super(view);
    }

    @Override
    public void login(LoginRequest request) {
        Api.getInstance().login(GsonUtil.GsonString(request))
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        addDisposable(disposable);
                        view.showLoadingDialog("請求發起");
                    }
                })
                .map(new Function<LoginResponse, LoginResponse>() {
                    @Override
                    public LoginResponse apply(final LoginResponse baseBean) throws Exception {
                        DbHelper.getDbHelper().saveBaseInfo(baseBean);//保存登錄數據
                        return baseBean;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<LoginResponse>() {
                    @Override
                    public void accept(LoginResponse baseBean) throws Exception {
                        view.loginSuccess();
                        view.dismissLoadingDialog();
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        view.dismissLoadingDialog();
                        view.showToast("失敗:" + throwable.getMessage());
                        ExceptionHelper.handleException(throwable);
                    }
                });;
    }


}

請求完畢後如果需要數據存儲或數據的中轉處理,建議是在轉換回主線程前用map處理返回數據,並且用DbHelper的方法進行數據存儲。然後再回到主線處理界面上的事項。

這樣看從view層查看到presenter層就可以直觀明瞭的查看到 請求和返回 的處理邏輯。

那麼我們現在來了解下rxjava2.0和retrofit2.0是怎麼結合

public class BaseApiImpl implements BaseApi {
    private volatile static Retrofit retrofit = null;
    protected Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
    protected OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();

    public BaseApiImpl(String baseUrl) {
        retrofitBuilder.addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(new GsonBuilder()
                        .setLenient()
                        .create()
                ))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpBuilder.addInterceptor(getLoggerInterceptor()).build())
                .baseUrl(baseUrl);
    }

    /**
     * 構建retroft
     *
     * @return Retrofit對象
     */
    @Override
    public Retrofit getRetrofit() {
        if (retrofit == null) {
            //鎖定代碼塊
            synchronized (BaseApiImpl.class) {
                if (retrofit == null) {
                    retrofit = retrofitBuilder.build(); //創建retrofit對象
                }
            }
        }
        return retrofit;

    }


    @Override
    public OkHttpClient.Builder setInterceptor(Interceptor interceptor) {
        return httpBuilder.addInterceptor(interceptor);
    }

    @Override
    public Retrofit.Builder setConverterFactory(Converter.Factory factory) {
        return retrofitBuilder.addConverterFactory(factory);
    }

    /**
     * 日誌攔截器
     * 將你訪問的接口信息
     *
     * @return 攔截器
     */
    public HttpLoggingInterceptor getLoggerInterceptor() {
        //日誌顯示級別
        HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.HEADERS;
        //新建log攔截器
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Log.d("ApiUrl", "--->" + message);
            }
        });
        loggingInterceptor.setLevel(level);
        return loggingInterceptor;
    }
}

BaseApiImpl是用來給Retrofit實體類工具 繼承的基礎類,這裏將retrofit的實例創建好,並且可以在此做基礎的日誌攔截。下面爲實體類工具代碼:

public class Api extends BaseApiImpl {
    private static Api api = new Api(RetrofitService.BASE_URL);

    public Api(String baseUrl) {
        super(baseUrl);
    }


    public static RetrofitService getInstance() {
        return api.getRetrofit().create(RetrofitService.class);
    }
}

在我們上面presenter的登錄調用就用了Api.getInstance()方法。目的就是拿到RetrofitService的retrofit實體類,進行網絡的調用。

下面來看下RetrofitService代碼:

public interface RetrofitService {

    String BASE_URL = "http://IP:port/api/";


    @GET("self/getUserSelfInfo")
    Observable<LoginResponse> login(@Body String request);

}

@GET和@Body都是Retrofit的使用方式。而Observable就是rxjava的訂閱類,此類可以進行異步的發起。

我們在寫完這些後,以後有新的網絡請求只需要在RetrofitService這個文件中添加對應的請求。就可以在presenter中直接請求了。

這樣就對以後的代碼編寫節約了很多時間。

現在我們再看下Realm的使用:

public class DbHelper {
    public static volatile DbHelper dbHelper;

    public static DbHelper getDbHelper(){
        if(dbHelper ==null){
            synchronized (DbHelper.class){
                if(dbHelper == null){
                    dbHelper =new DbHelper();
                }
            }
        }
        return dbHelper;
    }

    public static RealmResults<BaseInfo> getBaseInfos(){
        return Realm.getDefaultInstance().where(BaseInfo.class).findAll();
    }
    public void saveBaseInfo(final LoginResponse baseBean){
        Realm.getDefaultInstance().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                BaseInfo ba = new BaseInfo();
                ba.setName(baseBean.getData().getUserName());
                ba.setUserId(baseBean.getData().getUserId());
                realm.copyToRealm(ba);
            }
        });
    }
}

除去初始的Realm配置。直接看DbHepler,使用單例保證dbHelper不會在同一時間被不同線程調用,再將添加所需要的數據庫操作方法即可。

 

這樣就有完整的基礎框架。如果大家對這樣的代碼感興趣的話可以點擊下方下載。

mvp+rxjava2+retrofit2.0+realm基礎代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章