Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android進階篇 MVP+Retrofit+RxJava框架結合

android進階篇 MVP+Retrofit+RxJava框架結合

編輯:關於Android編程

一、前言

MVP模式是當前比較主流的框架,主要是由它的優點來決定的吧。本文結合了MVP+Retrofit+RxJava三大主流框架(MVP應該叫模式吧)寫了一個demo【裡面從簡單的“登錄”例子,之後到“IP地址查詢”,再到相對貼近實際項目的“獲取豆瓣TOP250的電影”】,一開始可能會覺得不容易理解,但是真正理解了之後,開發、維護就不是那麼痛苦的事情了。

二、Demo介紹

2.1、需要具備哪些知識

讀這篇文章之前,你需要了解的知識有:

1、MVP【點這裡看百度百科介紹】
2、Retrofit 2.0
3、RxJava(點擊這裡看—不錯的一個Retrofit+RxJava結合的例子)
4、Butterknife的使用
5、狀態欄一體化(android狀態欄一體化)
6、CallBack回調思想(說白了就是:成功還是失敗了,你總的告訴我一聲,我好通知V層來處理[這裡可以不用回調,在代碼中使用EventBus或者傳遞一個Handler過來也可以,不建議這樣操作])

2.2、Demo中使用到的工具類、技術

MVP 模式 Retrofit 網絡請求 RxJava 異步 Klog 花樣日志 CallBack 回調思想 丟棄Handler RecycleView 高效地顯示大量數據—>未來替代listview gridview的控件 CommonAdapter 鴻洋大神的RecycleView通用適配器 Loadmore 加載更多 也是借助鴻洋大神的RecycleView通用適配器(添加FootHeader)實現的 Glide 高效的圖片加載庫 android-Ultra-Pull-To-Refresh 下拉刷新 ClearEditText 自定義”帶清除所有內容”的輸入框控件 狀態欄一體化(設置狀態欄的顏色與app主題色一致 沒有過渡感)

2.3、優勢

1、MVP 高度解耦 提高代碼質量
2、Retrofit+RxJava最強的網絡訪問組合
3、功能易擴展 易維護 易測試

2.4、數據源

豆瓣TOP250的電影 https://api.douban.com/v2/movie/top250?start=0&count=10
查詢IP地址 http://ip.taobao.com/service/getIpInfo.php?ip=1.1.1.1

2.5、MVP淺析

1)、MVP的優點:

1、模型與視圖完全分離,我們可以修改視圖而不影響模型
2、可以更高效地使用模型,因為所有的交互都發生在一個地方——Presenter內部
3、我們可以將一個Presenter用於多個視圖,而不需要改變Presenter的邏輯。這個特性非常的有用,因為視圖的變化總是比模型的變化頻繁。
4、如果我們把邏輯放在Presenter中,那麼我們就可以脫離用戶接口來測試這些邏輯(單元測試)【以上優點參考了百度百科的“MVP模式“】

2)、以登錄為例的MVP自理解圖
這裡寫圖片描述

2.6、當下最快的網絡訪問(Retrofit +RxJava)

用熟悉之後你會發現,網絡訪問就是這麼簡單,這麼快.優點我就不一一說了,網上太多的介紹.

三、效果圖與分包說明

3.1、效果圖

不多說,先來看效果圖
這裡寫圖片描述

3.2、分包說明

分包有很多種分法,我這裡用了我常用的分包方法,僅供參考。
這裡寫圖片描述
說明<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPqO6YWRhcHRlciZuZGFzaDsmZ3Q7ysrF5Mb3tcTA4KOsYmFzZSZuZGFzaDsmZ3Q7u/m0obXExeTWw8Dgo6xiZWFuJm5kYXNoOyZndDvKtczlttTP86OsZXhjZXB0aW9uJm5kYXNoOyZndDvS7LOjtKbA7bbUz/OjrGh0dHAmbmRhc2g7Jmd0O834wufP4LnYo6x1aSZuZGFzaDsmZ3Q7y/nT0LXE0rPD5qOosPzAqGZyYWdtZW50ob4vdWkvZnJhZ21lbnShv6Opo6x1dGlscyZuZGFzaDsmZ3Q7uaS+38Dgo6x3aWRnZXQmbmRhc2g7Jmd0O9fUtqjS5b/YvP7A4KGjPC9wPg0KPGg0IGlkPQ=="33其他說明">3.3、其他說明

Demo閱讀指南 :先看登錄的Demo(入門),理解之後再看IP地址查詢(深入),最後看獲取豆瓣TOP250的電影(淺出)
使用第三方庫說明 :為了快速寫出這個demo,在一些方便走了捷徑(有時間的可以自己用原生的寫法),比如RecycleView的適配器,我就用了鴻洋大神的通用適配器(CommonAdapter),還有使用Butterknife來代替findviewbyid,但是看過郭霖大神寫的性能優化一篇博客,說是實際開發中最好慎重使用依賴注入,會降低app的性能和效率,我在這裡為了方便就直接使用了.

四、登錄demo

4.1、布局

布局簡單就不貼了

4.2、接口類

為什麼要使用接口,之前已經說過了,這裡之所以寫在一個類中,也是為了便於管理,不至於項目看上去有太多的類。

/**
 * 登錄的關聯類
 * Created by HDL on 2016/7/22.
 */
public class LoginContract {
    /**
     * V視圖層
     */
    interface ILoginView {
        Context getCurContext();//獲取上下文對象,用於保存數據等
        void showProgress();//可以顯示進度條
        void hideProgress();//可以隱藏進度條
        void showInfo(String info);//提示用戶,提升友好交互
        void showErrorMsg(String msg);//發生錯誤就顯示錯誤信息
        void toMain();//跳轉到主頁面
        void toRegister();//跳轉到注冊頁面
        UserInfo getUserLoginInfo();//獲取用戶登錄信息
    }
    /**
     * P視圖與邏輯處理的連接層
     */
    interface ILoginPresenter {
        void login();//橋梁就是登錄了
    }
    /**
     * 邏輯處理層
     */
    interface ILoginModel {
        void login(UserInfo userInfo, OnHttpCallBack callBack);//登錄
        void saveUserInfo(Context context, UserInfo user,String token);//登錄成功就保存用戶信息
    }

4.3、View層(LoginActivity)

展示數據,處理用戶交互

/**
 * 登錄頁面
 * (看例子之前看一遍下面直白的解釋,看完之後再看一遍就更明白MVP模式了)
 * --------M層   對P層傳遞過來的userInfo進行登錄(網絡請求)判斷,處理完成之後將處理結果回調給P層
 * --------P層   傳遞完數據給M層處理之後,實例化回調對象,成功了就通知V層登錄成功,失敗了就通知V層顯示錯誤信息
 * --------V層   負責響應用戶的交互(獲取數據---->提示操作結果)
 */
public class LoginActivity extends BaseActivity implements LoginContract.ILoginView {
    //省略ButterKnife綁定頁面控件的代碼
    private LoginPresenter mLoginPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        ButterKnife.inject(this);
        tvTitle.setText("用戶登錄");
        mLoginPresenter = new LoginPresenter(this);
    }
    @Override
    public Context getCurContext() {
        return mActivity;
    }
    @Override
    public void showProgress() {
        pbProgress.setVisibility(View.VISIBLE);
    }
    @Override
    public void hideProgress() {
        pbProgress.setVisibility(View.GONE);
    }
    @Override
    public void showInfo(String info) {
        ToastUtils.showToast(mActivity, info);
    }
    @Override
    public void showErrorMsg(String msg) {
        ToastUtils.showToast(mActivity, msg);
    }
    @Override
    public void toMain() {
        startActivity(new Intent(mActivity, QueryIPActivity.class));
    }
    @Override
    public void toRegister() {
        startActivity(new Intent(mActivity, RegisterActivity.class));
    }
    @Override
    public UserInfo getUserLoginInfo() {
        return new UserInfo(etLoginUserName.getText().toString().trim(), etLoginPwd.getText().toString().trim());
    }
    public void onRegister(View view) {
        toRegister();
    }
    @OnClick({R.id.iv_title_back, R.id.btn_login})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.iv_title_back:
                finish();
                break;
            case R.id.btn_login:
                mLoginPresenter.login();
                break;
        }
    }
}

這樣看來,View層是不是就少寫了很多代碼了!

4.4、Presenter層

獲取V層數據,交給M層處理,將處理結果通知給V層

/**
 * 登錄的橋梁(View和Model的橋梁)-------P通過將V拿到的數據交給M來處理  P又將處理的結果回顯到V
 * 說白點就是P中new出M和V 然後通過調用它們兩個的方法來完成操作
 * 

* (看例子之前看一遍下面的直白的解釋,看完之後再看一遍就更明白MVP模式了) * --------V層 負責響應用戶的交互(獲取數據---->提示操作結果) * --------P層 傳遞完數據給M層處理之後,實例化回調對象,成功了就通知V層登錄成功,失敗了就通知V層顯示錯誤信息 * --------M層 對P層傳遞過來的userInfo進行登錄(網絡請求)判斷,處理完成之後將處理結果回調給P層 * Created by HDL on 2016/7/22. */ public class LoginPresenter implements LoginContract.ILoginPresenter { private LoginContract.ILoginView mLoginView; private LoginContract.ILoginModel mLoginModel; public LoginPresenter(LoginContract.ILoginView mLoginView) { this.mLoginView = mLoginView; mLoginModel = new LoginModel(); } /** * 登錄 */ @Override public void login() { mLoginView.showProgress(); //顯示登錄進度條 final int i = 0; mLoginModel.login(mLoginView.getUserLoginInfo(), new OnHttpCallBack() { @Override public void onSuccessful(TokenResult tokenResult) { mLoginView.hideProgress();//隱藏進度條 mLoginView.toMain();//跳轉到主頁面 mLoginModel.saveUserInfo(mLoginView.getCurContext(), mLoginView.getUserLoginInfo(), tokenResult.getToken());//保存用戶數據 mLoginView.showInfo("登錄成功,您的用戶toekn為:" + tokenResult.getToken());//提示用戶登錄成功 } @Override public void onFaild(String errorMsg) { mLoginView.hideProgress();//隱藏進度條 mLoginView.showErrorMsg(errorMsg);//登錄失敗 顯示錯誤信息 } }); } }

4.5、Model層

具體的業務處理

/**
 * 登錄的業務處理類
 * Created by  on 2016/7/22.
 */
public class LoginModel implements LoginContract.ILoginModel {
    /**
     * 登錄的具體業務處理--------網絡請求都在這裡做喽
     * --------V層   負責響應用戶的交互(獲取數據---->提示操作結果)
     * --------P層   傳遞完數據給M層處理之後,實例化回調對象,成功了就通知V層登錄成功,失敗了就通知V層顯示錯誤信息
     * --------M層   對P層傳遞過來的userInfo進行登錄(網絡請求)判斷,處理完成之後將處理結果回調給P層
     *
     * @param userInfo P層傳遞過來的數據
     * @param callBack P層傳遞過來的回調對象----------說白了就是成功還是失敗了,你總的告訴我一聲,我好通知V層來處理[這裡可以不用回調,在代碼中使用EventBus或者傳遞一個Handler過來也可以,不建議這樣操作]
     */
    @Override
    public void login(final UserInfo userInfo, final OnHttpCallBack callBack) {
        //登錄的網絡請求
        RetrofitUtils.newInstence(GlobalField.BASEURL)//實例化Retrofit對象
                .create(APIService.class)//創建Rxjava---->LoginService對象
                .userLogin(userInfo.getUserName(), userInfo.getPwd())//調用登錄的接口
                .subscribeOn(Schedulers.newThread())//在新線程中執行登錄請求
                .observeOn(AndroidSchedulers.mainThread())//在主線程中執行
                .subscribe(new Subscriber>() {//網絡(登錄)請求回調
                    @Override
                    public void onCompleted() {
                        //完成的時候調用
                    }
                    @Override
                    public void onError(Throwable e) {
                        KLog.e(e.getMessage() + "--");
                        e.printStackTrace();
                        //失敗的時候調用-----一下可以忽略 直接 callBack.onFaild("請求失敗");
                        if (e instanceof HttpException) {
                            HttpException httpException = (HttpException) e;
                            //httpException.response().errorBody().string()
                            int code = httpException.code();
                            if (code == 500 || code == 404) {
                                callBack.onFaild("服務器出錯");
                            }
                        } else if (e instanceof ConnectException) {
                            callBack.onFaild("網絡斷開,請打開網絡!");
                        } else if (e instanceof SocketTimeoutException) {
                            callBack.onFaild("網絡連接超時!!");
                        } else {
                            callBack.onFaild("發生未知錯誤" + e.getMessage());
                            KLog.e("Myloy", e.getMessage());
                        }
                    }
                    @Override
                    public void onNext(UserHttpResult loginResultUserHttpResult) {
                        if (loginResultUserHttpResult.getResultCode() == 0) {
                            callBack.onSuccessful(loginResultUserHttpResult.getData());//登錄成功------獲取完數據,返回給P---P獲取到數據之後就將數據交回給V
                        } else {
                            callBack.onFaild("用戶名或密碼錯誤!");//登錄失敗
                        }
                    }
                });
    }
    /**
     * 將用戶信息保存在sp中
     *
     * @param context
     * @param user
     */
    @Override
    public void saveUserInfo(Context context, UserInfo user, String token) {
        KLog.e("開始保存用戶信息" + user.toString());
        context.getSharedPreferences(GlobalField.USERINFO_SP_NAME, Context.MODE_PRIVATE).edit()
                .putString("userName", user.getUserName())
                .putString("pwd", user.getPwd())
                .putString("address", user.getAddress())
                .putString("phone", user.getPhone())
                .putString("token", token)
                .commit();
    }
}

4.6、Retofit網絡請求工具

Retrofit使用注意事項,baseurl要以“/”結束 在Service中Get(“—”)/Post(“—-“)不能以“/”開始

/**
 * Retofit網絡請求工具類
 * Created by HDL on 2016/7/29.
 */
public class RetrofitUtils {
    private static final int READ_TIMEOUT = 60;//讀取超時時間,單位  秒
    private static final int CONN_TIMEOUT = 12;//連接超時時間,單位  秒
    private static Retrofit mRetrofit;
    private RetrofitUtils() {
    }
    public static Retrofit newInstence(String url) {
        mRetrofit = null;
        OkHttpClient client = new OkHttpClient();//初始化一個client,不然retrofit會自己默認添加一個
        client.setReadTimeout(READ_TIMEOUT, TimeUnit.MINUTES);//設置讀取時間為一分鐘
        client.setConnectTimeout(CONN_TIMEOUT, TimeUnit.SECONDS);//設置連接時間為12s
        mRetrofit = new Retrofit.Builder()
                .client(client)//添加一個client,不然retrofit會自己默認添加一個
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        return mRetrofit;
    }
}

4.7、APIService公共請求接口類

/**
 * API--接口  服務[這裡處理的是同一的返回格式 resultCode  resultInfo Data --->這裡的data才是返回的結果,T就是泛型 具體返回的been對象或集合]
 * Created by HDL on 2016/8/3.
 */
public interface APIService {
    /**
     * 用戶登錄的接口
     *
     * @param username 用戶名
     * @param pwd      密碼
     * @return RxJava 對象
     */
    @POST("okhttp/UserInfoServlert")
    Observable> userLogin(@Query("username") String username, @Query("pwd") String pwd);
    /**
     * 查詢ip地址信息的接口
     *
     * @param ip 需查詢的ip
     * @return RxJava 對象
     */
    @GET("service/getIpInfo.php")
    Observable> queryIp(@Query("ip") String ip);
    /**
     * 查詢豆瓣排名前250的電影
     *
     * @param start 從第幾部開始
     * @param count 幾頁(一頁有12部)
     * @return
     */
    @GET("v2/movie/top250")
    Observable getMovies(@Query("start") int start, @Query("count") int count);
}

五、IP查詢

為了減少文章的篇幅這裡就不貼查詢IP的了:如果你對這個demo感興趣,請下載demo去自己看,代碼裡面的注釋自認為挺清楚的.(Demo下載地址在最後)

六、獲取豆瓣TOP250的電影

6.1、效果圖

這裡寫圖片描述

6.2、布局

總布局:



    
    
        
    

item布局比較簡單就不貼了,需要的可到demo中查看

6.3、接口類

/**
 * 獲取豆瓣top250的關聯類---------這裡主要是抽出MVP中三層的接口,好處就是改需求很方便,使得代碼結構更加清晰
 * Created by HDL on 2016/7/22.
 */
public class MovieContract {
    /**
     * V視圖層
     */
    interface IMovieView {
        void showBottom(int lastIndex);
        Context getCurContext();//獲取上下文對象
        void showProgress();//顯示進度條
        void hideProgress();//隱藏進度條
        void showData(List movies);//顯示數據到View上
        void showInfo(String info);//提示用戶,提升友好交互
    }
    /**
     * P視圖與邏輯處理的連接層
     */
    interface IMoviePresenter {
        void getMovie();//獲取數據
        void loadMoreMovie();//加載更多
    }
    /**
     * M邏輯(業務)處理層
     */
    interface IMovieModel {
        void getMovie(int start, int count, OnHttpCallBack callBack);//獲取信息
    }
}

6.4、View層

/**
 * 豆瓣排名前250名
 */
public class MovieActivity extends BaseActivity implements MovieContract.IMovieView {
    MoviePresenter mMoviePresenter;
    @InjectView(R.id.tv_title)
    TextView tvTitle;
    private ProgressDialog mProgressDialog;
    @InjectView(R.id.rv_movie_list)
    RecyclerView rvMovieList;
    @InjectView(R.id.store_house_ptr_frame)
    PtrFrameLayout storeHousePtrFrame;
    private TextView load_more;//加載更多的按鈕
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();
        mMoviePresenter = new MoviePresenter(this);
        mMoviePresenter.getMovie();//啟動軟件時默認加載
    }
    /**
     * 初始化布局
     */
    private void initView() {
        setContentView(R.layout.activity_movie);
        ButterKnife.inject(this);
        tvTitle.setText("豆瓣Top250的電影");
        initPtr();
        rvMovieList.setLayoutManager(new LinearLayoutManager(mActivity));//設置為listview的布局
        rvMovieList.setItemAnimator(new DefaultItemAnimator());//設置動畫
        rvMovieList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));//添加分割線
    }
    /**
     * 初始化(配置)下拉刷新組件
     */
    private void initPtr() {
        //下面是一些基礎的配置,直接拿來用就可以 不用深究
        storeHousePtrFrame.setResistance(1.7f);
        storeHousePtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);
        storeHousePtrFrame.setDurationToClose(200);
        storeHousePtrFrame.setDurationToCloseHeader(1000);
        storeHousePtrFrame.setPullToRefresh(false);
        storeHousePtrFrame.setKeepHeaderWhenRefresh(true);
        StoreHouseHeader header = new StoreHouseHeader(this);
        float scale = getResources().getDisplayMetrics().density;
        header.setPadding(0, (int) (15 * scale + 0.5f), 0, (int) (15 * scale + 0.5f));
        header.initWithString("HDL");//自定義頭顯示的字樣,設置圖片的話看另外的api
        header.setTextColor(Color.RED);
        header.setBackgroundColor(Color.parseColor("#11000000"));
        storeHousePtrFrame.setHeaderView(header);//添加頭
        storeHousePtrFrame.addPtrUIHandler(header);//同時也要加上這一句
        storeHousePtrFrame.setPtrHandler(new PtrHandler() {
            @Override
            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
                return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);
            }
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                mMoviePresenter.loadMoreMovie();//下拉刷新的時候加載更多數據
                frame.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        storeHousePtrFrame.refreshComplete();
                    }
                }, 150);//為了增加用戶體驗 延遲0.15s再通知刷新結束
            }
        });
    }
    @Override
    public void showBottom(int lastIndex) {
        load_more.setText("點擊加載更多");//設置最底下的加載更多顯示的內容    加載中-->點擊加載更多
        rvMovieList.scrollToPosition(lastIndex);
    }
    @Override
    public Context getCurContext() {
        return this;
    }
    @Override
    public void showProgress() {
        mProgressDialog = ProgressDialog.show(this, "提示", "正在獲取中,請稍後...");
    }
    @Override
    public void hideProgress() {
        mProgressDialog.hide();
    }
    /**
     * 顯示數據
     *
     * @param movies
     */
    @Override
    public void showData(List movies) {
        //鴻洋大神的通用適配器(真的很好用哦)
        CommonAdapter commonAdapter = new CommonAdapter(this, R.layout.movie_item, movies) {
            @Override
            protected void convert(ViewHolder holder, Movies.SubjectsBean subjectsBean, int position) {
                String title = (position + 1) + "、" + subjectsBean.getTitle() + "/" + subjectsBean.getOriginal_title();
                holder.setText(R.id.tv_movie_title, title);//設置電影名
                String doc = "";
                for (Movies.SubjectsBean.DirectorsBean directorsBean : subjectsBean.getDirectors()) {
                    doc += directorsBean.getName() + "  ";
                }
                holder.setText(R.id.tv_movie_doc, "導演:" + doc);
                String casts = "";
                for (Movies.SubjectsBean.CastsBean castsBean : subjectsBean.getCasts()) {
                    casts += castsBean.getName() + "  ";
                }
                holder.setText(R.id.tv_movie_art, "主演:" + casts);
                String genres = "";
                for (String genre : subjectsBean.getGenres()) {
                    genres += genre + " ";
                }
                holder.setText(R.id.tv_movie_type, subjectsBean.getYear() + " / " + genres);//年份+分級
                holder.setText(R.id.tv_movie_grade, subjectsBean.getRating().getAverage() + "");//評分
                ImageView iv_pic = holder.getView(R.id.iv_movie_pic);
                Glide.with(mActivity)
                        .load(subjectsBean.getImages().getSmall())
                        .diskCacheStrategy(DiskCacheStrategy.ALL)//加快顯示速度---緩存在本地磁盤
                        .into(iv_pic);//圖片
            }
        };
        /**
         * 配置加載更多(通用適配器裡面的類哦)
         */
        LoadMoreWrapper mLoadMoreWrapper = new LoadMoreWrapper(commonAdapter);//加載更多的包裝器(傳入通用適配器)
        View view = View.inflate(mActivity, R.layout.load_more, null);
        //要設置一下的布局參數,因為布局填充到包裝器的時候,自己的一些屬性會無效
        LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        view.setLayoutParams(mLayoutParams);
        load_more = (TextView) view.findViewById(R.id.tv_load_more);
        //監聽點擊加載更多事件
        load_more.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                load_more.setText("加載中...");//點擊加載更多-->加載中
                mMoviePresenter.loadMoreMovie();
            }
        });
        mLoadMoreWrapper.setLoadMoreView(view);
        rvMovieList.setAdapter(mLoadMoreWrapper);//注意  這裡添加的是包裝器 不是適配器哦
    }
    @Override
    public void showInfo(String info) {
        ToastUtils.showToast(this, info);
    }
    @OnClick(R.id.iv_title_back)
    public void onClick() {
        finish();
    }
}

6.5、Presenter層

/**
 * P層
 * Created by HDL on 2016/8/3.
 */
public class MoviePresenter implements MovieContract.IMoviePresenter {
    MovieContract.IMovieModel mIMovieModel;//M層
    MovieContract.IMovieView mIMovieView;//V層
    public  int start = 0;//從第幾個開始
    public  int count = 4;//請求多少個
    List mMovies = new ArrayList<>();//請求到的電影信息對象集合
    public MoviePresenter(MovieContract.IMovieView mIMovieView) {
        this.mIMovieView = mIMovieView;
        mIMovieModel = new MovieModel();
    }
    @Override
    public void getMovie() {
        mIMovieView.showProgress();//通知V層顯示對話框
        //每次刷新加載4個
        mIMovieModel.getMovie(start, count, new OnHttpCallBack() {//有一個請求結果的回調,即我調用請求電影信息的方法了,M層要返回一個成功還是失敗的信息給我
            @Override
            public void onSuccessful(Movies movies) {//獲取電影信息成功了,返回movies對象
                mIMovieView.hideProgress();//通知V層隱藏對話框
                mMovies.addAll(movies.getSubjects());//追加數據
                mIMovieView.showData(mMovies);//將獲取到的信息顯示到界面之前
                mIMovieView.showBottom(start - 5);//實現換頁效果
            }
            @Override
            public void onFaild(String errorMsg) {
                mIMovieView.hideProgress();//通知V層隱藏對話框
                mIMovieView.showInfo(errorMsg);//通知V層顯示錯誤信息
            }
        });
        start = start + 4;//改變請求的起點
    }
    /**
     * 加載更多
     */
    @Override
    public void loadMoreMovie() {
        getMovie();
    }
}

6.6、Model層

/**
 * 具體的邏輯(業務)處理了
 * Created by HDL on 2016/8/3.
 */
public class MovieModel implements MovieContract.IMovieModel {
    @Override
    public void getMovie(int start, int count, final OnHttpCallBack callBack) {
        RetrofitUtils.newInstence(GlobalField.MOVIE_TOP250_URL)
                .create(APIService.class)
                .getMovies(start, count)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Subscriber() {
                    @Override
                    public void onCompleted() {
                    }
                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        //失敗的時候回調-----一下可以忽略 直接 callBack.onFaild("請求失敗");
                        if (e instanceof HttpException) {
                            HttpException httpException = (HttpException) e;
                            //httpException.response().errorBody().string()
                            int code = httpException.code();
                            if (code == 500 || code == 404) {
                                callBack.onFaild("服務器出錯");
                            }
                        } else if (e instanceof ConnectException) {
                            callBack.onFaild("網絡斷開,請打開網絡!");
                        } else if (e instanceof SocketTimeoutException) {
                            callBack.onFaild("網絡連接超時!!");
                        } else {
                            callBack.onFaild("發生未知錯誤" + e.getMessage());
                            KLog.e(e.getMessage());
                        }
                    }
                    @Override
                    public void onNext(Movies movies) {
                        callBack.onSuccessful(movies);//請求成功---回調
                        KLog.e(movies.toString());
                    }
                });
    }
}

七、Demo下載

有一些簡單的代碼就沒有貼出來,可以下demo去看一下

這是demo的GitHub的地址 https://github.com/huangdali/newkjdemo/

代碼有誤的地方請多多指出,共同進步,有問題的請留言、評論。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved