Android架構系列-基於MVP建立適合本身的架構

本文基於MVP整理出了一套適合本身的架構php

0 Android架構系列文章

該系列文章會不斷更新Android項目開發中一些好的架構和小技巧java

系列一 Android架構系列-基於MVP建立適合本身的架構
系列二 Android架構系列-如何優美的寫Intent
系列三 Android架構系列-開發規範
系列四 Android架構系列-封裝本身的okhttp
系列五 Android架構系列-MVP架構的實際應用android

1 爲何選擇MVP

MVP架構是當前比較成熟的Android架構,還有其餘架構好比最初始的MVC和MVVM。MVC相對於較爲落後,MVVM使用DataBind,普及性不如MVP。因此最終決定本身設計的框架是基於MVP思想進行總結的框架。git

選擇MVP框架的緣由之一也是google官方的示例中MVP sample已是完成,證實google官方對於MVP的認可度。github

官方項目地址:
github.com/googlesampl…api

一個較爲詳細的官方項目源碼解析的文章:
www.infoq.com/cn/articles…緩存

2 MVP簡介

具體的MVP架構相關文章網上已經很是多了,具體的能夠自行查找。MVP的存在主要是因爲普通MVC架構會致使項目中activity過於臃腫,當項目愈來愈大後,代碼可讀性大大下降。服務器

MVP的思想是將activity做爲view層,只負責與xml的渲染和監聽事件,具體處理數據邏輯放到一個新定義的Present層。減小了activity負責的事情。而且能夠強迫開發者養成分模塊功能開發的思想。開發前設計好功能模塊,而不是像之前同樣寫流水帳同樣寫代碼。從頭寫到尾。網絡

MVP
MVP

3 個人總結

本身根據MVP的思想和一些好的源碼總結了一套適合字的框架。真正的架構是依賴義務存在的,因此建議你們能總結出適合本身項目的代碼。架構

3.1 目錄分配

在目錄分配上決定採用根據功能模塊進行劃分,而不是全部activty在一個目錄的方法。相似google的例子:

目錄
目錄

緣由幾點:

  1. 功能模塊劃分更爲清晰,對於之後代碼閱讀和新人接手更好
  2. 適用於模塊化開發,好比之後又是一個新項目,老項目的登陸模塊、用戶模塊、論壇模塊等待能夠整個複製出來重用
  3. 雖然網上提過按照多個模塊劃分可能會有公用的頁面。我認爲複製一份也沒什麼,不會形成很大的冗餘代碼,而且對於頁面來講萬一之後某個模塊頁面有自定義修改不會對其餘影響。(畢竟頁面的靈活性要求很高,不適合架構抽出來通用的)
  4. 須要抽出來的獨立於功能模塊的應該是common_util 和 common_widget,分別是通用工具層和通用自定義控件層

具體例子分配以下:

Sample目錄
Sample目錄

  • GloabApp 全局Application
  • RootAct 啓動頁面
  • Base目錄 基礎activity fragment存放
  • util目錄 通用工具
  • mywidget 通用自定義控件
  • SampleModule Sample功能模塊。裏面包含獨立的MVP的接口

3.2 Model層

Model層中又能夠分爲Api層和Cache層。

3.2.1 Api層

主要是網絡獲取數據信息等接口。

使用了本身二次封裝過的Retrofit+Okhttp+Gson組合。詳細能夠參見文章:www.jianshu.com/p/283d1a7a0…

示例SampleApi:

public class SampleApi extends BaseApi {

    private static final String mBaseUrl = "http://192.168.3.1/";

    private ApiStore mApiStore;

    public SampleApi() {
        super(mBaseUrl);
        mApiStore = mRetrofit.create(ApiStore.class);
    }

    /** * 獲取xxx數據 * @param uid * @param callback */
    public void getSampleInfo(String uid, ApiCallback<GetSampleInfoRet> callback) {
        Call<GetSampleInfoRet> call = ((ApiStore)mApiStore).getSampleInfo(uid);
        call.enqueue(new RetrofitCallback<GetSampleInfoRet>(callback));
    }

    public interface ApiStore {
        @FormUrlEncoded
        @POST("test_retrofit.php")
        Call<GetSampleInfoRet> getSampleInfo(@Field("uid") String uid);
    }
}複製代碼

3.2.2 Cache層

本地緩存部分數據。

使用了ASimpleCache緩存開源代碼。詳細能夠參見文章:www.jianshu.com/p/25c107ed7…

示例SampleCache:

public class SampleCache extends BaseCache {

    private final String KEY_NEWEST_SAMPLE_INFO = "sample_newest_info";

    public SampleCache(Context context) {
        super(context);
    }

    /** * 保存sample信息 * @param serializable */
    public void saveNewestSample(Serializable serializable) {
        mCache.put(KEY_NEWEST_SAMPLE_INFO, serializable);
    }

    /** * 獲取sample信息 * @return */
    public SampleInfo getNewestSampleInfo() {
        return (SampleInfo) mCache.getAsObject(KEY_NEWEST_SAMPLE_INFO);
    }

    /** * 移除緩存 */
    public void removeNewestSampleInfo() {
        mCache.remove(KEY_NEWEST_SAMPLE_INFO);
    }
}複製代碼

3.3 Data層

實體化數據類。

3.4 Presenter層

Presenter層又能夠分爲Contract協議接口,和具體的Presenter處理

3.4.1 Contract層

負責約定view層和presenter層的接口,view和presenter實現相應接口,最終達到解耦的目的。

SampleContract示例:

public interface SampleContract {

    interface View {
        void showSample(SampleInfo sampleInfo);     //顯示sample

        void errorGetSample(String msg);    //顯示錯誤信息
    }

    interface Presenter {
        void getNewestSample(); //獲取當前最新的xxx
    }
}複製代碼

3.4.2 Presenter層

負責從model層獲取數據、整理數據、行爲處理等。處理後調用view顯示數據。

SamplePresenter示例:

public class SamplePresenter extends BasePresenter implements SampleContract.Presenter {

    private SampleContract.View mView;
    private SampleApi mApi;
    private SampleCache mCache;

    public SamplePresenter(SampleContract.View view) {
        mView = view;

        mApi = new SampleApi();
        mCache = new SampleCache(GlobalApp.getInstance().getContext());
    }

    @Override
    public void getNewestSample() {
        //先從緩存獲取
        SampleInfo sampleInfo = mCache.getNewestSampleInfo();

        if(sampleInfo == null) {
            //從網絡獲取
            mApi.getSampleInfo("uid", new BaseApi.ApiCallback<GetSampleInfoRet>() {
                @Override
                public void onSuccess(GetSampleInfoRet ret) {
                    //緩存
                    mCache.saveNewestSample(ret.data);

                    //頁面顯示
                    mView.showSample(ret.data);
                }

                @Override
                public void onError(int err_code, String err_msg) {
                    //服務端返回錯誤碼
                    mView.errorGetSample(err_msg);
                }

                @Override
                public void onFailure() {
                    //網絡請求或者解析錯誤
                    mView.errorGetSample("服務器請求錯誤");
                }
            });
        } else {
            mView.showSample(sampleInfo);
        }
    }
}複製代碼

3.5 view層

即平時所說的activity、fragment等。繼承自SampleContract的view接口,只負責UI相關顯示刷新等。因爲拉出了presenter層,view層的代碼變得極爲清晰

SampleActivity示例:

public class SampleActivity extends BaseActivity implements SampleContract.View {

    @BindView(R.id.txtName)
    TextView txtName;

    @BindView(R.id.imgAvatar)
    ImageView imgAvatar;

    private SampleContract.Presenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);
        ButterKnife.bind(this);

        mPresenter = new SamplePresenter(this);
    }

    @Override
    public void showSample(SampleInfo sampleInfo) {
        txtName.setText(sampleInfo.sample_name);
        Glide.with(this)
                .load(sampleInfo.avatar)
                .into(imgAvatar);
    }

    @Override
    public void errorGetSample(String msg) {
        //錯誤信息
    }

}複製代碼

4 總結

以上代碼Github地址:
github.com/tsy12321/Ba…

注:該項目會作成一個基礎的項目框架,包含各類封裝好的工具,底層庫和MVP架構,還在不斷更新中,歡迎關注提Issue!

結尾

更多文章關注個人公衆號

個人公衆號
個人公衆號
相關文章
相關標籤/搜索