Android--Retrofit+RxJava的簡單封裝(三)


1,繼續接着上一篇的講講,話說如果像上一篇這樣的話,那么我們每一次請求一個結構都要創建一堆的Retrofit對象,而且代碼都是相同的,我們可以試試封裝一下

先創建一個HttpMethods類,將Retrofit對象創建封裝起來

HttpMethods.java

package com.qianmo.retrofitdemo.http;

import com.qianmo.retrofitdemo.entry.MovieEntity;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Created by wangjitao on 2016/11/3 0003.
 * 對Retrofit的的簡單封裝
 */
public class HttpMethods {

    public static final String BASE_URL = "https://api.douban.com/v2/movie/";
    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;

    private MovieService movieService;

    //先構造私有的構造方法
    private HttpMethods() {
        //手動創建一個OkHttpClient並設置超時時間
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();
        movieService = retrofit.create(MovieService.class);
    }

    //創建單例
    public static class SingleonHolder {
        private static final HttpMethods instance = new HttpMethods();
    }

    //獲取單例
    public static HttpMethods getInstance() {
        return SingleonHolder.instance;
    }

    /**
     *
     * @param start 起始位置
     * @param count 獲取長度
     * @param subscriber 傳遞過來的觀察者對象
     */
    public void getTopMovie(int start, int count, Subscriber<MovieEntity> subscriber) {
        movieService.getTopMovie(start, count)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

在直接在Activity中進行調用

package com.qianmo.retrofitdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.qianmo.retrofitdemo.entry.MovieEntity;
import com.qianmo.retrofitdemo.http.HttpMethods;
import com.qianmo.retrofitdemo.http.MovieService;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.tv_show)
    TextView tvShow;
    @Bind(R.id.btn_request)
    Button btnRequest;

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

    @OnClick({R.id.btn_request})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_request:
                getMovie();
                break;
        }
    }

    //請求網絡數據
    private void getMovie() {

//        //https://api.douban.com/v2/movie/top250?start=0&count=10 目標地址
//        String baseUrl = "https://api.douban.com/v2/movie/";
//
//        //創建Retrofit對象
//        Retrofit retrofit = new Retrofit.Builder()
//                .baseUrl(baseUrl)
//                .addConverterFactory(GsonConverterFactory.create())
//                .build();
//
//        MovieService movieService = retrofit.create(MovieService.class);
//        Call<MovieEntity> call = movieService.getTopMovie(0, 10);
//        call.enqueue(new Callback<MovieEntity>() {
//            @Override
//            public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
//                tvShow.setText(response.body().getTitle());
//            }
//
//            @Override
//            public void onFailure(Call<MovieEntity> call, Throwable t) {
//                tvShow.setText(t.getMessage());
//            }
//        });

        //第二種
//        String baseUrl = "https://api.douban.com/v2/movie/";
//
//        Retrofit retrofit = new Retrofit.Builder()
//                .baseUrl(baseUrl)
//                .addConverterFactory(GsonConverterFactory.create())
//                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//                .build();
//        MovieService movieService = retrofit.create(MovieService.class);
//
//        movieService.getTopMovie(0, 10)
//                .subscribeOn(Schedulers.io())
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(new Subscriber<MovieEntity>() {
//                    @Override
//                    public void onCompleted() {
//                        Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
//                    }
//
//                    @Override
//                    public void onError(Throwable e) {
//                        tvShow.setText(e.getMessage());
//                    }
//
//                    @Override
//                    public void onNext(MovieEntity movieEntity) {
//                        tvShow.setText(movieEntity.getTitle());
//                    }
//                });
        HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber<MovieEntity>() {
            @Override
            public void onCompleted() {
                Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                tvShow.setText(e.getMessage());
            }

            @Override
            public void onNext(MovieEntity movieEntity) {
                tvShow.setText(movieEntity.getTitle());
            }
        });
    }


}

但是現在存在一個問題,當存在相同格式的數據時候  我們應該怎么封裝,一般來說我們后台返給我們的數據是這樣的:

{
 "resultCode": 0,
 "resultMessage": "成功",
 "data": {}
}

 主要的數據是data,然后通過code來判斷是否請求成功  由於data里面的數據是多變的 可以是一個對象也可以是一個數組 這時候我們需要創建一個HttpResult

package com.qianmo.retrofitdemo.http;

/**
 * Created by Administrator on 2016/11/3 0003.
 */
public class HttpResult<T> {
    private int resultCode ;
    private String resultMessage ;

    private T data ;


}

用過我們這次借口的同學都知道我們這次接口其實不是這樣的,先來看看我們這次的數據結構吧

{
    "count": 10, 
    "start": 0, 
    "total": 250, 
    "subjects": [], 
    "title": "豆瓣電影Top250"
}

我們打算通過count的數量來判斷請求是否成功,所以吧HttpResult類修改成下面

package com.qianmo.retrofitdemo.http;

/**
 * Created by Administrator on 2016/11/3 0003.
 */
public class HttpResult<T> {
//    常用形式
//    private int resultCode ;
//    private String resultMessage ;
//
//    private T data ;

    //本次接口的數據結構
    private int count;
    private int start;
    private int total;
    private String title;

    //用來模仿Data
    private T subjects;


    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }


    public T getSubjects() {
        return subjects;
    }

    public void setSubjects(T subjects) {
        this.subjects = subjects;
    }


    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("title=" + title + " count=" + count + " start=" + start);
        if (null != subjects) {
            sb.append(" subjects:" + subjects.toString());
        }
        return sb.toString();
    }

}

在正常服務器返回的數據下code=200或者code=0的時候是表示成功的,但是由於我們這次的接口沒有這一塊的內容,所以打算使用count字段來判斷,當coun = 0的時候表示沒有數據,請求失敗,所以這里我們需要在HttpMethod類中添加一個判斷的方法

/**
     * 用來處理請求的code
     * @param <T>
     */
    private class HttpResultFunc<T> implements Func1<HttpResult<T>, T> {
        @Override
        public T call(HttpResult<T> tHttpResult) {
            if (tHttpResult.getCount() == 0) {
                throw new ApiException(100);
            }
            return tHttpResult.getSubjects();
        }
    }

所以getMovie() 方法修改成了

/**
     * 用於獲取豆瓣電影Top250的數據
     * @param subscriber  由調用者傳過來的觀察者對象
     * @param start 起始位置
     * @param count 獲取長度
     */
    public void getTopMovie(Subscriber<List<Subject>> subscriber, int start, int count){

        movieService.getTopMovie(start, count)
                .map(new HttpResultFunc<List<Subject>>())
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
}

ok,在修改一下activity中的調用方法

HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber<List<Subject>>() {
            @Override
            public void onCompleted() {
                Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                tvShow.setText(e.getMessage());
            }

            @Override
            public void onNext(List<Subject> subjects) {
                StringBuffer sb = new StringBuffer();
                for (Subject subject : subjects) {
                    sb.append(subject.toString());
                }
                tvShow.setText(sb);
            }
        });

讓我們看一下效果:(截取的動態圖又太大了!!上傳不了)

 

 但是這也不是我們想要的最終結果,在請求數據的時候顯示加載框,在請求完成的時候或者請求出錯的時候影藏掉加載框,這樣的話才算一個正常的網絡請求框架。由於使用了RxJava,所以要創建一個類,繼承與Subscriber,由於Subscriver對象中有四個方法,onStart、onNext、onError、onCompleted方法,我們需要在onStart中顯示進度框,在onCompleted和onError中隱藏掉加載框,由於activity只關心最后的數據,所以我們需要寫一個接口回調,將onNext方法中的數據傳遞給activity,讓activity去處理邏輯。

SubscriberOnNextListenter.java

package com.qianmo.retrofitdemo.http;

/**
 * Created by Administrator on 2016/11/3 0003.
 */
public interface SubscriberOnNextListenter<T> {
    void next(T t);
}

ProgressSubscriber.java

package com.qianmo.retrofitdemo.http;

import android.content.Context;
import android.widget.Toast;

import rx.Subscriber;

/**
 * Created by wangjitao on 2016/11/3 0003.
 */
public class ProgressSubscriber<T> extends Subscriber<T> {

    private SubscriberOnNextListenter mSubscriberOnNextListenter;
    private Context context;

    public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) {
        this.mSubscriberOnNextListenter = mSubscriberOnNextListenter;
        this.context = context;
    }

    @Override
    public void onStart() {
    }

    @Override
    public void onCompleted() {
        Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onError(Throwable e) {
        Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNext(T t) {
        mSubscriberOnNextListenter.next(t);
    }
}

再來修改一下我們activity調用的代碼

package com.qianmo.retrofitdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.qianmo.retrofitdemo.entry.Subject;
import com.qianmo.retrofitdemo.http.HttpMethods;
import com.qianmo.retrofitdemo.http.ProgressSubscriber;
import com.qianmo.retrofitdemo.http.SubscriberOnNextListenter;

import java.util.List;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import rx.Subscriber;

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.tv_show)
    TextView tvShow;
    @Bind(R.id.btn_request)
    Button btnRequest;


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

    @OnClick({R.id.btn_request})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_request:
                getMovie();
                break;
        }
    }

    //請求網絡數據
    private void getMovie() {

//        //https://api.douban.com/v2/movie/top250?start=0&count=10 目標地址
//        String baseUrl = "https://api.douban.com/v2/movie/";
//
//        //創建Retrofit對象
//        Retrofit retrofit = new Retrofit.Builder()
//                .baseUrl(baseUrl)
//                .addConverterFactory(GsonConverterFactory.create())
//                .build();
//
//        MovieService movieService = retrofit.create(MovieService.class);
//        Call<MovieEntity> call = movieService.getTopMovie(0, 10);
//        call.enqueue(new Callback<MovieEntity>() {
//            @Override
//            public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
//                tvShow.setText(response.body().getTitle());
//            }
//
//            @Override
//            public void onFailure(Call<MovieEntity> call, Throwable t) {
//                tvShow.setText(t.getMessage());
//            }
//        });

        //第二種
//        String baseUrl = "https://api.douban.com/v2/movie/";
//
//        Retrofit retrofit = new Retrofit.Builder()
//                .baseUrl(baseUrl)
//                .addConverterFactory(GsonConverterFactory.create())
//                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//                .build();
//        MovieService movieService = retrofit.create(MovieService.class);
//
//        movieService.getTopMovie(0, 10)
//                .subscribeOn(Schedulers.io())
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(new Subscriber<MovieEntity>() {
//                    @Override
//                    public void onCompleted() {
//                        Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
//                    }
//
//                    @Override
//                    public void onError(Throwable e) {
//                        tvShow.setText(e.getMessage());
//                    }
//
//                    @Override
//                    public void onNext(MovieEntity movieEntity) {
//                        tvShow.setText(movieEntity.getTitle());
//                    }
//                });
        //第三種
//        HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber<List<Subject>>() {
//            @Override
//            public void onCompleted() {
//                Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
//            }
//
//            @Override
//            public void onError(Throwable e) {
//                tvShow.setText(e.getMessage());
//            }
//
//            @Override
//            public void onNext(List<Subject> subjects) {
//                StringBuffer sb = new StringBuffer();
//                for (Subject subject : subjects) {
//                    sb.append(subject.toString());
//                }
//                tvShow.setText(sb);
//            }
//        });
        SubscriberOnNextListenter subscriberOnNextListenter = new SubscriberOnNextListenter() {
            @Override
            public void next(Object o) {

            }
        };
        //第四種
        HttpMethods.getInstance()
                .getTopMovie(0, 10, new ProgressSubscriber<List<Subject>>(
                        new SubscriberOnNextListenter<List<Subject>>() {
                            @Override
                            public void next(List<Subject> subjects) {
                                StringBuffer sb = new StringBuffer();
                                for (Subject subject : subjects) {
                                    sb.append(subject.toString());
                                }
                                tvShow.setText(sb);
                            }
                        }, MainActivity.this));

    }


}

再加上取消加載的接口和封裝的progress就基本上完成了

package com.qianmo.retrofitdemo.http;

public interface ProgressCancelListener {
    void onCancelProgress();
}

 

package com.qianmo.retrofitdemo.http;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;

/**
 * Created by liukun on 16/3/10.
 */
public class ProgressDialogHandler extends Handler {

    public static final int SHOW_PROGRESS_DIALOG = 1;
    public static final int DISMISS_PROGRESS_DIALOG = 2;

    private ProgressDialog pd;

    private Context context;
    private boolean cancelable;
    private ProgressCancelListener mProgressCancelListener;

    public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener,
                                 boolean cancelable) {
        super();
        this.context = context;
        this.mProgressCancelListener = mProgressCancelListener;
        this.cancelable = cancelable;
    }

    private void initProgressDialog(){
        if (pd == null) {
            pd = new ProgressDialog(context);

            pd.setCancelable(cancelable);

            if (cancelable) {
                pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialogInterface) {
                        mProgressCancelListener.onCancelProgress();
                    }
                });
            }

            if (!pd.isShowing()) {
                pd.show();
            }
        }
    }

    private void dismissProgressDialog(){
        if (pd != null) {
            pd.dismiss();
            pd = null;
        }
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SHOW_PROGRESS_DIALOG:
                initProgressDialog();
                break;
            case DISMISS_PROGRESS_DIALOG:
                dismissProgressDialog();
                break;
        }
    }

}

progressSubscriber.java

package com.qianmo.retrofitdemo.http;

import android.content.Context;
import android.widget.Toast;

import java.net.ConnectException;
import java.net.SocketTimeoutException;

import rx.Subscriber;

/**
 * Created by wangjitao on 2016/11/3 0003.
 */
public class ProgressSubscriber<T> extends Subscriber<T> implements ProgressCancelListener {

    private SubscriberOnNextListenter mSubscriberOnNextListenter;
    private ProgressDialogHandler mProgressDialogHandler;
    private Context context;

    public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) {
        this.mSubscriberOnNextListenter = mSubscriberOnNextListenter;
        this.context = context;
        mProgressDialogHandler = new ProgressDialogHandler(context, this, true);
    }

    /**
     * 在開始訂閱的時候顯示加載框
     */
    @Override
    public void onStart() {
        if (mProgressDialogHandler != null) {
            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
        }
    }

    /**
     * 在完成的時候進行影藏
     */
    @Override
    public void onCompleted() {
        Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
        dismissProgressDialog();
    }

    /**
     * 在出錯的時候也進行影藏
     *
     * @param e
     */
    @Override
    public void onError(Throwable e) {
        if (e instanceof SocketTimeoutException) {
            Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態", Toast.LENGTH_SHORT).show();
        } else if (e instanceof ConnectException) {
            Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
        dismissProgressDialog();
    }

    @Override
    public void onNext(T t) {
        mSubscriberOnNextListenter.next(t);
    }

    @Override
    public void onCancelProgress() {
        if (!this.isUnsubscribed()) {
            this.unsubscribe();
        }
    }

    private void showProgressDialog() {
        if (mProgressDialogHandler != null) {
            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
        }
    }

    private void dismissProgressDialog() {
        if (mProgressDialogHandler != null) {
            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();
            mProgressDialogHandler = null;
        }
    }
}

最后看一下效果

  

  

 

  

  

  

  

  


免責聲明!

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



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