Android MVP模式實踐

前段時間做項目時有用到一個比較常用的設計模式-MVP模式,我個人比較喜歡有優(yōu)美的結構的代碼,我始終相信代碼也是一種藝術,現(xiàn)在就特地將這一部分拿出來分享哈,自己也可以再熟悉熟悉。
OK,廢話不多說先上個圖,來看看我的代碼中MVP模式的應用:


mvpimg
mvpimg
  • View 代表的是Android中對應的Activity,F(xiàn)ragment或View等與UI相關的。(view通常含有Presenter的引用)
  • ViewInterface 用來提取一些可重用的功能,比如Pregress等以及方便的更改View,類之間更加的模塊化。使用時,只需要讓View去實現(xiàn)這個接口.
  • Presenter 相當于一個路由,又來自View的轉發(fā)請求,以及Model回調的數(shù)據(jù)實體。(Presenter持有Model層的應用,以及ViewInterface的引用)
  • Model 業(yè)務邏輯層。提取數(shù)據(jù)從Database,或云端API,緩存等,然后再對數(shù)據(jù)加以處理,再分發(fā)給Presenter去處理。

OK,來個栗子看看。一個根據(jù)圖書的isbn,從豆瓣的RestFul API中提取圖書的細節(jié)信息,再返回給前臺界面。

1.在View層中

/**
 * ViewInterface
 * 定義一些通用的view接口
 */
public interface LoadDataView {
    /***
     * 耗時操作,加載數(shù)據(jù),顯示Progress
     */
    void showLoading();
    /***
     * 隱藏Progress
     */
    void hideLoading();
}
/**
 * 更細小的,用來顯示圖書細節(jié)的View接口
 */
public interface LoadBookView extends LoadDataView {
    void showDetailsView(BookEntity entity);
}

/***
 * Fragment,屬于View層,實現(xiàn)了ViewInterface(LoadBookView)
 */
public class BookDetailFragment extends Fragment implements LoadBookView{
    /**圖書條形碼ISBN號*/
    public static final String ISBN = "9787121060748";
    /**持Presenter對象*/
    private BookDetailsPresenter presenter;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initWidget();
        presenter = new BookDetailsPresenter(getActivity(), ISBN); // 實例化一個presenter對象
        presenter.setView(this); //讓Presenter持一個ViewInterface實例(LoadBookView)
        presenter.loadData(); //告訴Presenter快給我加載Data
    }    

     @Override
    public void showDetailsView(BookEntity entity) {
        //更新UI等操作
    }

    @Override
    public void showLoading() {
        rlProgress.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        rlProgress.setVisibility(View.GONE);
    }
}

2.在Presenter層中

public class BookDetailsPresenter {
    /**持一個Model層的對象,用來從網(wǎng)頁接口Rest Api中提取數(shù)據(jù)*/
    private RestApi restApi = null;
    /**一個ViewInterface對象,用來回調Data給View*/
    private LoadBookView loadBookView;
    private String isbn;

    public BookDetailsPresenter(Context context, String isbn) {
        restApi = new RestApiImpl(context);
        this.isbn =isbn;
    }
    public void setView(LoadBookView loadBookView) {
        this.loadBookView = loadBookView;
    }
    public void loadData() {
        loadBookView.showLoading();
        //耗時操作,開個線程異步的加載數(shù)據(jù)
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                restApi.getBookDetailByIsbn(isbn, bookDetailsCallback);
            }
        });
        thread.start();
    }
    //匿名內部類,接收bookDetailCallback的回調數(shù)據(jù)
    private RestApi.BookDetailsCallback bookDetailsCallback = new RestApi.BookDetailsCallback() {
        @Override
        public void onBookEntityLoaded(BookEntity bookEntity) {
            notifyDataLoadedSuccessful(bookEntity);
            BookDetailsPresenter.this.loadBookView.hideLoading();
        }

        @Override
        public void onError(Exception e) {
            //異常后的相關處理
        }
    };

    /***
    * 通知獲取數(shù)據(jù)成功了,趕快通知UI更新吧
    */
    private void notifyDataLoadedSuccessful(final BookEntity bookEntity) {
        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                BookDetailsPresenter.this.loadBookView.showDetailsView(bookEntity);
            }
        });
    }  
}

3.在Model層中

/***
* 整個應用程序需要的數(shù)據(jù)實體類
*/
public class BookEntity {
    //一些set,get方法
}

/**
 * 一個接口,用來從rest api api獲得數(shù)據(jù),它的實現(xiàn)在RestApiImpl中
 */
public interface RestApi {
    String API_ISBN_BASE_URL = "https://api.douban.com/v2/book/isbn/";
    /***
    * 更細小的接口,用來將獲取到的數(shù)據(jù),回調給它的調用者
    */
    interface BookDetailsCallback {
        void onBookEntityLoaded(BookEntity bookEntity);
        void onError(Exception e);
    }
    /**
     * 從網(wǎng)絡獲取數(shù)據(jù),然后通過bookDetailCallback回調給Presenter
     * @param isbn
     * @param bookDetailsCallback
     */
    void getBookDetailByIsbn(final String isbn, final BookDetailsCallback bookDetailsCallback);

}

好了核心的代碼就貼到這兒了,每個類關鍵的地方都偶注釋,整個Demo的代碼在github上,有興趣可以下來看看。這篇文章主要是從我的這個項目graduation中分離出來的, 主要借鑒了architecting-android-the-clean-way, 現(xiàn)在拿出來分享給大家,有不合理的地方也請多多指正,感謝萬分!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,983評論 25 709
  • 轉載至:http://www.itdecent.cn/p/9a6845b26856 “Android MVP 詳解...
    SnowDragonYY閱讀 10,416評論 5 241
  • Android MVP模式實踐總結(附帶簡單例子) 最近在做畢業(yè)設計,題目不是很難,但是后來發(fā)現(xiàn)功能有點多,感覺是...
    lawliex閱讀 703評論 1 8
  • 暑期即將落幕,這不短的也不長的暑假,于孩子們而言應當是快樂的。沁兒就是如此,快樂著,幸福著。 首...
    真申閱讀 566評論 0 2
  • 琨琨出生后,一直圍著他轉,每次和老公視頻,鏡頭瞄準我?guī)酌腌姾?,一定會對著他的一顰一笑,他緊握的拳頭,像投降...
    丹丹在路上閱讀 504評論 0 3

友情鏈接更多精彩內容