Android使用RxJava+Retrofit2+Okhttp+MVP練習的APP


Android使用RxJava+Retrofit2+Okhttp+MVP練習的APP


項目截圖


 

 
 


 

這是我的目錄結構

 

 

 

 

五步使用RxJava+Retrofit2+Okhttp+RxCache

 第一步:導包

    compile 'io.reactivex:rxjava:1.1.8'
    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
    compile 'com.github.VictorAlbertos.RxCache:core:1.4.6'

  

第二步:新建API接口

 

public interface GanHuoService {

    @GET("data/{type}/{number}/{page}")
    Observable<DataResults> getDataResults(
            @Path("type") String type,
            @Path("number") int number,
            @Path("page") int page
    );
}

  

第三步:新建緩存接口
/**
 * 緩存API接口
 *
 * @LifeCache設置緩存過期時間. 如果沒有設置@LifeCache , 數據將被永久緩存理除非你使用了 EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup .
 * EvictProvider可以明確地清理清理所有緩存數據.
 * EvictDynamicKey可以明確地清理指定的數據 DynamicKey.
 * EvictDynamicKeyGroup 允許明確地清理一組特定的數據. DynamicKeyGroup.
 * DynamicKey驅逐與一個特定的鍵使用EvictDynamicKey相關的數據。比如分頁,排序或篩選要求
 * DynamicKeyGroup。驅逐一組與key關聯的數據,使用EvictDynamicKeyGroup。比如分頁,排序或篩選要求
 */
public interface CacheProviders {
    //緩存時間 1天
    @LifeCache(duration = 7, timeUnit = TimeUnit.DAYS)
    Observable<Reply<List<DataResults>>> getHomeTypes(Observable observable, DynamicKey userName, EvictDynamicKey evictDynamicKey);

}
 

  

第四步:新建retrofit抽象類
 
public abstract class RetrofitUtils {

    private static Retrofit mRetrofit;
    private static OkHttpClient mOkHttpClient;

    /**
     * 獲取Retrofit對象
     *
     * @return
     */
    protected static Retrofit getRetrofit() {

        if (null == mRetrofit) {

            if (null == mOkHttpClient) {
                mOkHttpClient = OkHttp3Utils.getOkHttpClient();
            }

            //Retrofit2后使用build設計模式
            mRetrofit = new Retrofit.Builder()
                    //設置服務器路徑
                    .baseUrl(Constant.API_SERVER + "/")
                    //添加轉化庫,默認是Gson
                    .addConverterFactory(GsonConverterFactory.create())
                    //添加回調庫,采用RxJava
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    //設置使用okhttp網絡請求
                    .client(mOkHttpClient)
                    .build();
        }

        return mRetrofit;
    }

}
 

  

第五步:新建HttpData類 用於統一管理請求
 
/*
 * 所有的請求數據的方法集中地
 * 根據MovieService的定義編寫合適的方法
 * 其中observable是獲取API數據
 * observableCahce獲取緩存數據
 * new EvictDynamicKey(false) false使用緩存  true 加載數據不使用緩存
 */
public class HttpData extends RetrofitUtils {

    private static File cacheDirectory = FileUtil.getcacheDirectory();
    private static final CacheProviders providers = new RxCache.Builder()
            .persistence(cacheDirectory)
            .using(CacheProviders.class);
    protected static final GanHuoService service = getRetrofit().create(GanHuoService.class);

    private static class SingletonHolder {
        private static final HttpData INSTANCE = new HttpData();
    }

    public static HttpData getInstance() {
        return SingletonHolder.INSTANCE;
    }


    public void getHomeInfo(Observer<DataResults> observer,  boolean isUseCache,String type, int number, int page) {
        Observable observable= service.getDataResults(type,number,page);
        Observable observableCahce=providers.getHomeTypes(observable,new DynamicKey("首頁"),new EvictDynamicKey(!isUseCache)).map(new HttpResultFuncCcche<List<DataResults>>());
        setSubscribe(observableCahce,observer);
    }

    /**
     * 插入觀察者
     *
     * @param observable
     * @param observer
     * @param <T>
     */
    public static <T> void setSubscribe(Observable<T> observable, Observer<T> observer) {
        observable.subscribeOn(Schedulers.io())
                .subscribeOn(Schedulers.newThread())//子線程訪問網絡
                .observeOn(AndroidSchedulers.mainThread())//回調到主線程
                .subscribe(observer);
    }

    /**
     * 用來統一處理RxCacha的結果
     */
    private class HttpResultFuncCcche<T> implements Func1<Reply<T>, T> {

        @Override
        public T call(Reply<T> httpResult) {
            return httpResult.getData();
        }
    }

}

  

 
搭建完成,可以像這樣請求數據,需要寫到Model里面的
public class HomeFragmentModel {

    public void loadData(final OnLoadDataListListener listener,boolean isUseCache ,String type, int number, int page) {
        HttpData.getInstance().getHomeInfo(new Observer<DataResults>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                listener.onFailure(e);
            }

            @Override
            public void onNext(DataResults homeDto) {
                listener.onSuccess(homeDto);
            }
        }, isUseCache,type,number,page);
    }
} 
 

MVC (Model-View-Controller)

M是指邏輯模型,V是指視圖模型,C則是控制器。一個邏輯模型可以對於多種視圖模型
使用MVC的目的是將M和V的實現代碼分離,方便擴展,便於以后的管理
從開發者的角度,MVC把應用程序的邏輯層與界面是完全分開的,最大的好處是:界面設計人員可以直接參與到界面開發,程序員就可以把精力放在邏輯層上。
雖然理論上可以實現,但實踐起來還是感覺不能完全分開...
Android中也可以說采用了當前比較流行的MVC框架,在Android中: 
  1) 視圖層(View):一般采用XML文件進行界面的描述,使用的時候可以非常方便的引入,但是用xml編寫了,又需要在Acitvity聲明並且實例化。
  2) 控制層(Controller):Android的控制層的重任通常落在了眾多的Acitvity的肩上,要通過Activity交割Model業務邏輯層處理,這樣做的另外一個原因是Android中的Acitivity的響應時間是5s,如果耗時的操作放在這里,程序就很容易被回收掉。
  3) 模型層(Model):對數據庫的操作、對網絡等的操作都應該在Model里面處理,當然對業務計算等操作也是必須放在的該層的。

MVP

MVP 就是基於MVC 的模式上的一個演化版本。在MVC模式中,Activity應該是屬於View這一層。而實質上,它既承擔了View,同時也包含一些Controller的東西在里面。隨着項目的迭代更新,這對開發很不友好,耦合度也原來越高,項目越來越難維護,而MVP 就是解決這樣的痛點。把Activity的View和Controller抽離出來就變成了View和Presenter。

MVP的優點:

  • 模型與視圖完全分離,我們可以修改視圖而不影響模型

  • 可以更高效地使用模型,因為所有的交互都發生在一個地方——Presenter內部

  • 我們可以將一個Presenter用於多個視圖,而不需要改變Presenter的邏輯。這個特性非常的有用,因為視圖的變化總是比模型的變化頻繁。

  • 如果我們把邏輯放在Presenter中,那么我們就可以脫離用戶接口來測試這些邏輯(單元測試)

首頁是Model層:業務邏輯和實體模型,所以Model層我只放業務邏輯
public class HomeFragmentModel {

    public void loadData(final OnLoadDataListListener listener,boolean isUseCache ,String type, int number, int page) {
        HttpData.getInstance().getHomeInfo(new Observer<DataResults>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                listener.onFailure(e);
            }

            @Override
            public void onNext(DataResults homeDto) {
                listener.onSuccess(homeDto);
            }
        }, isUseCache,type,number,page);
    }
}
 
然后是view層: View 對應於Activity或者fragment,負責View的繪制以及與用戶交互
public interface HomeFragmentView {
    //顯示加載頁
    void showProgress();
    //關閉加載頁
    void hideProgress();
    //加載新數據
    void newDatas(DataResults data);
    //顯示加載失敗
    void showLoadFailMsg();

}

  

然后就是Presenter 負責完成View於Model間的交互
public class HomePresenter  implements OnLoadDataListListener<DataResults> {

    private HomeFragmentView mView;
    private HomeFragmentModel mModel;

    public HomePresenter(HomeFragmentView mView) {
        this.mView = mView;
        this.mModel=new HomeFragmentModel();
        mView.showProgress();
    }

    public void getDataResults(boolean isUseCache,String type, int number, int page) {
        mModel.loadData(this,isUseCache,type,number,page);
    }

    @Override
    public void onSuccess(DataResults data) {
        mView.newDatas(data);
        mView.hideProgress();
    }

    @Override
    public void onFailure(Throwable e) {
        Log.e("onFailure",e.toString());
        mView.showLoadFailMsg();
    }
}

  

最終回到Activity或者fragment
 
public class DiscoveryFragment extends BaseFragment implements HomeFragmentView {

     private HomePresenter homePresenter;


    @Override
    protected View initView(LayoutInflater inflater, ViewGroup container) {
        return inflater.inflate(R.layout.fragment_list, container, false);
    }


    @Override
    protected void initData(Bundle savedInstanceState) {
            homePresenter = new HomePresenter(this);
    }


    @Override
    protected void loadData() {
        getData(isFirst);
    }

    private void getData(boolean isUseCache) {
        switch (mTitle) {
            case "首頁":
                if (isTop) {
                    NOW_PAGE_FI = 1;
                }
                homePresenter.getDataResults(isUseCache,"all", fi_num, NOW_PAGE_FI);
                break;
               }
    }


    @Override
    public void newDatas(DataResults dataResults) {
        if (dataResults.isError()) {
            Snackbar.make(recyclerview, "服務器出問題啦", Snackbar.LENGTH_SHORT).show();
        } else {
            if (mTitle.equals("干貨")) {
                ganhuo_list = new ArrayList<>();
                ganhuo_list.addAll(dataResults.getResults());
            }
        }
    }

    private void clearAdapterResults() {
        switch (mTitle) {
            case "首頁":
                partAdapter.getResults().clear();
                break;
            case "妹紙":
                girlyAdapter.getResults().clear();
                break;
        }
    }

    @Override
    public void showLoadFailMsg() {
        Snackbar.make(recyclerview, "網絡不順暢嘞,更新不了數據啦", Snackbar.LENGTH_SHORT).show();
    }


    @Override
    public void showProgress() {

    }

    @Override
    public void hideProgress() {

    }
}

  

項目地址,歡迎star:
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM