天天看點

Android網絡程式設計Retrofit+Rxjava用法詳解一.簡介二.貼代碼

一.簡介

Retrofit是是Square公司開發的一款針對Android網絡請求的架構,Retrofit2底層基于OkHttp實作的,OkHttp現在已經得到Google官方認可,大量的app都采用OkHttp做網絡請求,其源碼詳見OkHttp Github。

二.貼代碼

1.首先在gradle中添加如下配置

compile 'com.google.code.gson:gson:2.6.2'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
           

這樣就将Retrofit+RxJava引入進來了

2.在manifest中添加網絡權限

<uses-permission android:name="android.permission.INTERNET" />
           

3.寫個接口FactoryInters,用來封裝get post方法

①這是get方法,一會在RetrofitBase中調用

@GET
    Observable<JSONObject> getData(
            @Url String url,
            @QueryMap Map<String, Object> params);
           

②這是post方法,一會在RetrofitBase中調用

@FormUrlEncoded
    @POST
    Observable<JSONObject> postData(
            @Url String url,
            @FieldMap Map<String, Object> params);
           

③這是上傳檔案的方法

有兩種寫法:使用@MultiPart注解,@Part注解檔案入參,則檔案入參類型應是List< okhttp3.MultipartBody.Part>;

                        不使用@Multipart注解,直接使用@Body注解檔案入參,則檔案入參類型應是okhttp3.MultipartBody

@Multipart
    @POST
    Observable<JSONObject> uploadFiles(
            @Url String url,
            @PartMap() Map<String, RequestBody> strParams,
            @Part() List<MultipartBody.Part> fileParams);
           

4.建立類RetrofitBase,用來具體實作get post方法

全局參數:

private static final String TAG = RetrofitBase.class.getSimpleName();
    protected static String BASEURL = Config.SERVER_ADDRESS;
    private static final long TIMEOUT = 5 * 1000;
    private FactoryInters service;
    private Retrofit retrofit;
    private Gson gson;
    private JsonParser jsonParser;
           

初始化

private RetrofitBase() {
        retrofit = new Retrofit.Builder()
                .baseUrl(BASEURL)
                .client(client())
                        //增加傳回值為Gson的支援(自定義MyGsonConverterFactory)
                .addConverterFactory(MyGsonConverterFactory.create())
                        //增加傳回值為Oservable<T>的支援
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

        service = retrofit.create(FactoryInters.class);
        gson = new GsonBuilder().setPrettyPrinting().create();
        jsonParser = new JsonParser();
    }
           
private static class SingletonHolder {
        private static final RetrofitBase INSTENCE = new RetrofitBase();
    }

    public static RetrofitBase getInstance() {
        return SingletonHolder.INSTENCE;
    }
           

獲得連接配接

private OkHttpClient client() {

        LauncherTrust launcherTrust = new LauncherTrust();

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .sslSocketFactory(sslSocketFactory(launcherTrust), launcherTrust)
                .hostnameVerifier(new AllowAllHostnameVerifier())
                .addInterceptor(interceptor)
                .retryOnConnectionFailure(false)//失敗重連
                .build();
        return okHttpClient;
    }

    private SSLSocketFactory sslSocketFactory(LauncherTrust launcherTrust) {

        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{launcherTrust}, new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
        return null;
    }

    static class LauncherTrust implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    LogInterceptor interceptor = new LogInterceptor(new LogInterceptor.Logger() {
        @Override
        public void log(String message) {
            Log.i(TAG, message);
        }
    });
           

重點!!!

get方法

public void getData(String url, Map<String, Object> params, SubListenerHelper listener) {
        Log.d(TAG, "[get請求參數] = \n" + gson.toJson(jsonParser.parse(gson.toJson(params))));
        service.getData(url, params)
                .compose(schedulersTransformer())
                .subscribe(listener);
    }
           

post方法

public void postData(String url, Map<String, Object> params, SubListenerHelper listener) {
        Log.d(TAG, "[post請求參數] = \n" + gson.toJson(jsonParser.parse(gson.toJson(params))));
        service.postData(url, params)
                .compose(schedulersTransformer())
                .subscribe(listener);
    }
           

上傳檔案

public void uploadFiles(String url, Map<String, RequestBody> strParams, List<MultipartBody.Part> fileParams, SubListenerHelper subscriberHelper) {
        service.uploadFiles(url, strParams, fileParams)
                .compose(schedulersTransformer())
                .subscribe(subscriberHelper);
    }
           

Observable

Observable.Transformer schedulersTransformer() {
        return new Observable.Transformer() {


            @Override
            public Object call(Object observable) {
                return ((Observable) observable)
                        .subscribeOn(Schedulers.io())//執行在io線程
                        .unsubscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());//主線程顯示
            }
        };
    }
           

上傳檔案時将map轉成List

public static List<MultipartBody.Part> fileList2PartList(Map<String, File> fileMap) {
        List<MultipartBody.Part> partList = new ArrayList<>(fileMap.size());
        for (Map.Entry<String, File> entry : fileMap.entrySet()) {
            String fileKey = entry.getKey();
            File file = entry.getValue();
            RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpg"), file);
            MultipartBody.Part part = MultipartBody.Part.createFormData(fileKey, file.getName(), requestBody);
            partList.add(part);
        }
        return partList;
    }
           

4.LogInterceptor類

public class LogInterceptor implements Interceptor {
    private static final Charset UTF8 = Charset.forName("UTF-8");

    public enum Level {
        NONE,
        BASIC,
        HEADERS,
        BODY
    }

    public interface Logger {
        void log(String message);

        int INFO = 800;
        Logger DEFAULT = new Logger() {
            @Override
            public void log(String message) {
                Platform.get().log(INFO, message, null);
            }
        };
    }

    public LogInterceptor() {
        this(Logger.DEFAULT);
    }

    public LogInterceptor(Logger logger) {
        this.logger = logger;
    }

    private final Logger logger;

    private volatile Level level = Level.BODY;

    /**
     * Change the level at which this interceptor logs.
     */
    public LogInterceptor setLevel(Level level) {
        if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead.");
        this.level = level;
        return this;
    }

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Level level = this.level;

        Request request = chain.request();
        if (level == Level.NONE) {
            return chain.proceed(request);
        }

        boolean logBody = level == Level.BODY;
        boolean logHeaders = logBody || level == Level.HEADERS;

        RequestBody requestBody = request.body();
        boolean hasRequestBody = requestBody != null;

        String requestStartMessage = request.method() + ' ' + request.url();
        if (!logHeaders && hasRequestBody) {
            requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
        }
        logger.log(requestStartMessage);

        if (logHeaders) {

            if (!logBody || !hasRequestBody) {
                logger.log("--> END " + request.method());
            } else if (bodyEncoded(request.headers())) {
                logger.log("--> END " + request.method() + " (encoded body omitted)");
            } else if (request.body() instanceof MultipartBody) {
                //如果是MultipartBody,會log出一大推亂碼的東東
            } else {
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);

                Charset charset = UTF8;
                MediaType contentType = requestBody.contentType();
                if (contentType != null) {
                    contentType.charset(UTF8);
                }

                logger.log(buffer.readString(charset));

//                logger.log(request.method() + " (" + requestBody.contentLength() + "-byte body)");
            }
        }

        long startNs = System.nanoTime();
        Response response = chain.proceed(request);
        long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
        logger.log(response.code() + ' ' + response.message() + " (" + tookMs + "ms" + ')');

        return response;
    }

    private boolean bodyEncoded(Headers headers) {
        String contentEncoding = headers.get("Content-Encoding");
        return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
    }

    private static String protocol(Protocol protocol) {
        return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1";
    }
}
           

5.MyGsonConverterFactory類

public class MyGsonConverterFactory extends Converter.Factory {

    private static final String TAG = MyGsonConverterFactory.class.getSimpleName();
    private final Gson gson;

    public static MyGsonConverterFactory create() {
        return create(new Gson());
    }

    public static MyGsonConverterFactory create(Gson gson) {
        return new MyGsonConverterFactory(gson);

    }


    private MyGsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }

    /**
     * 響應
     *
     * @param type
     * @param annotations
     * @param retrofit
     * @return
     */
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {

        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        Log.i(TAG, "responseBodyConverter");
        return new JsonResponseBodyConverter(gson, adapter);
    }

    /**
     * 請求
     *
     * @param type
     * @param parameterAnnotations
     * @param methodAnnotations
     * @param retrofit
     * @return
     */
    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {

        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        Log.i(TAG, "requestBodyConverter");
        return new JsonRequestBodyConverter<>(gson, adapter); //請求
    }
}
           

6.自定義請求類:JsonRequestBodyConverter

public class JsonRequestBodyConverter<T> implements Converter<T, RequestBody> {

    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final String TAG = JsonRequestBodyConverter.class.getSimpleName();
    private Gson gson;
    private TypeAdapter<T> adapter;

    public JsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override
    public RequestBody convert(T value) throws IOException {
        Log.i(TAG, "convert(T value)");
        String result = URLEncoder.encode(EncryptUtil.encryptByPublicKey(value.toString()), "utf-8");
        String postBody = gson.toJson(result); //對象轉化成json
        Log.i(TAG, "轉化後的資料:" + postBody);
        return RequestBody.create(MEDIA_TYPE, postBody);
    }
}
           

7.自定義響應類:JsonResponseBodyConverter

public class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {

    private static final String TAG = JsonResponseBodyConverter.class.getSimpleName();
    private final Gson mGson;//gson對象
    private final TypeAdapter<JSONObject> adapter;

    public JsonResponseBodyConverter(Gson gson, TypeAdapter<JSONObject> adapter) {
        this.mGson = gson;
        this.adapter = adapter;
    }


    @Override
    public T convert(ResponseBody responseBody) throws IOException {
        Log.i(TAG, "ResponseBody");
        String responseString = responseBody.string();
        String result = EncryptUtil.decryptByPublicKey(responseString);//解密
        Log.i(TAG, "解密的伺服器資料:" + result);

        JSONObject data = null;
        try {
            data = new JSONObject(result);
        } catch (JSONException e) {
            Log.i(TAG, "e:" + e);
            e.printStackTrace();
        }
        return (T) data;
    }
}
           

8.封裝的解析類SubListenerHelper

public abstract class SubListenerHelper extends Subscriber<JSONObject> {

    private static final String TAG = SubListenerHelper.class.getSimpleName();
    private boolean toastInfo = false;

    public abstract void onSuccess(JSONObject oriData, ServerResponse response);

    public abstract void onFailure(Throwable e);

    public abstract void onFinish();

    @Override
    public void onNext(JSONObject data) {
        ServerResponse response = ServerResponse.parseFromVolleyResponse(data);
        Log.i(TAG, "onNext data=" + data);
        //提示資訊
        if (!response.isSuccess) {
            if (toastInfo) {
                //如果伺服器傳回的status狀态不為1,就彈出伺服器給的吐司
                if (!TextUtils.isEmpty(response.msg)) {
                    Toast.makeText(AppContext.getContext(), response.msg, Toast.LENGTH_SHORT).show();
                } else if (!TextUtils.isEmpty(response.error)) {
                    Toast.makeText(AppContext.getContext(), response.error, Toast.LENGTH_SHORT).show();
                }
            }

        }
        if (null != response) {
            onSuccess(data, response);
        }
    }

    @Override
    public void onError(Throwable e) {
        Log.i(TAG, "onError e=" + e);
        onFailure(e);
    }

    @Override
    public void onCompleted() {
        onFinish();
    }

    public SubListenerHelper setToastInfo(boolean toastInfo) {
        this.toastInfo = toastInfo;
        return this;
    }
}
           

9.ServerResponse類

解析統一的格式

{"error":"E00000000","msg":"成功(沒有異常)","status":"1"}

這是我的傳回格式,不同格式可根據需求改代碼

public class ServerResponse {

    public static final int STATUS_SUCCESS = 1;
    public boolean isSuccess;

    public JSONObject data;
    public String error;
    public String msg;
    public int status;

    //對網絡傳回的json資料進行解析
    public static ServerResponse parseFromVolleyResponse(JSONObject object) {
        ServerResponse result = new ServerResponse();
        if (object != null) {
            result.status = object.optInt("status");
            result.isSuccess = result.status == STATUS_SUCCESS;
            result.error = object.optString("error");
            result.msg = object.optString("msg");
            //如果是資料就不能用result.data----object
            result.data = object.optJSONObject("data");
        }
        return result;
    }

    @Override
    public String toString() {
        return "ServerResponse{" +
                "data=" + data +
                ", error='" + error + '\'' +
                ", msg='" + msg + '\'' +
                ", status=" + status +
                '}';
    }
}