Retrofit2RxjavaDemo
                                
                                 Retrofit2RxjavaDemo copied to clipboard
                                
                                    Retrofit2RxjavaDemo copied to clipboard
                            
                            
                            
                        Retrofit2 with Rxjava[1], retreive data with non resutful data and get real data
Retrofit2RxjavaDemo
Help
è°æ¿æä½¿ç¨æ¬Demoåææ¶é´ï¼å¸ææäººå¯ä»¥å¨ä½¿ç¨æ¬Demoååææ¶é´æ¥å¸®å©ï¼æ¿æåcontributorçèç³»æ[email protected]ã
æ Dagger2示ä¾
Dagger2ç使ç¨å¯ä»¥ç®åç¸å ³ä¾èµï¼æä»¥æDagger2使ç¨éæå¨ä¸èµ·ï¼æä»¥ä¹åçæ dagger2æ¾å¨nodagger2 branchä¸ï¼ä¸ä½¿ç¨Dagger2çå¯ä»¥æ¥çè¿ä¸ªåæ¯ã
ææå±ç¤º
 

æ¬æä¸»è¦ä»ç»äºä½¿ç¨Retrofit2é
åRxjava[è¿éæRxjava1, ææ¶æªéé
Rxjava2] æ¥å¤çérestfulçç½ç»è¯·æ±ç»æãä¸è¬èè¨è¯·æ±çéRESTç»æå¦ä¸,å
æ¬ä¸ä¸ªcodeä»£è¡¨ç»æçç¶æåmsg表示æè¿°ï¼ä»¥ådata对åºççå®çæ°æ®ãæä»¬çç®çå°±æ¯ç´æ¥ådata对åºçæ°æ®ï¼å¦ææ¯æ°ç»é£ä¹åç乿¯æ°ç»list<databean>ç±»åçï¼å¦ææé误ï¼é£ä¹å°±ä¼è°ç¨onError()æ¹æ³ãæ´å¤æ¼ç¤ºææè¯·æ¥çvideoç®å½ä¸çè§é¢ã
{
	"code": 0,    //请æ±è¿åç¶æç  0表示æåï¼å
¶å®å为对åºçé误类å
	"msg": "è¯·æ±æå",    //请æ±è¿åç¶æ
	"data":
	{    //è¿åç»æ
		"phone": "010-62770334;010-62782051",    //çµè¯
		"website": "www.tsinghua.edu.cn",    //å®ç½
		"email": "[email protected]",    //é®ç®±
		"address": "åäº¬å¸æµ·æ·åºæ¸
å大å¦",    //å°å
		"zipcode": "0102770334",    //é®ç¼
		"name": "æ¸
å大å¦",    //妿 ¡åç§°
		"img": "http://img.jidichong.com/school/3.png",    //妿 ¡logoå¾ç
		"parent": "æè²é¨",    //é¶å±é¨é¨
		"type": " 211 985",    //妿 ¡ç±»å
		"profile": "xasd",   //ç®ä»
		"info": "é¢å£«ï¼68人 å士ç¹ï¼198个 ç¡å£«ç¹ï¼181个",    //说æ
		"city": "å京"   //æå¨çå¸
	}
}
èRetrofit2 请æ±çç»æä¸è¬é½å为Header åBodyãå¨è·åè¿äºæ°æ®ååå¨Rxjava subscriber ä¸çonNext()æ¥å¤çæ¯è¾éº»ç¦ãæä»¥è¿ä¸ªdemoä»ç»äºå¦ä½ç»æRetrofit2ä¸Rxjava1æ¥å¤çæ°æ®å¹¶å¨æåæ¶å¾å°dataåæ®µçæ°æ®ï¼æå¡ç«¯è¿åæé误æ¯è¿å ¥onError(),彿¯å个å®ä½çæ¶åï¼å¨onNextä¸å°±ç´æ¥å¾å°è¿ä¸ªç»æï¼å¦ææ¯ä¸ä¸ªæ°ç»çæ¶åï¼åæ¯è¿åList<Entity> è¿ç§å½¢å¼ãåæ¶ä¹ç®åäºå®ä¹gsonå®ä½ä¸ç¨æ¯æ¬¡é½å codeï¼ msgè¿æ ·ä¸å±ã
ä½¿ç¨æ¹æ³ï¼
1. é 置对åºçå¤å±å®ä½ã
ä¾å¦ä¸é¢ãå¼åä¸ä¸è¬é½éæ åçREST齿¯ä¸ä¸ªæ°æ®(ç¾åº¦å¼æ¾å¹³å°çæ¥å£å°±åºæ¬é½æ¯è¿ç§å½¢å¼)ï¼ä¸ä¸ªç¶æç åä¸ä¸ªæ¶æ¯ãå ¶ä¸dataçç±»åæ¯æ³åï¼å¯ä»¥å¨çæè¯·æ±çapiæå®å®é è¿åçç±»åï¼å¦æä¸ºç©ºçæ åµå¯ä»¥ä½¿ç¨Stringã ècode åmessageæ¯å¯¹åºäºæå¡ç«¯å®ä¹ç代ç codeåè¿åçé误信æ¯ãå¦æä½ çåå°åå°å段ä¸åï¼ä½ å¯ä»¥æéè¦ä¿®æ¹è¿ä¸ªHttpResultçç¸åºå段ã
	{
	    // code 为è¿åçç¶æç , message 为è¿åçæ¶æ¯, æ¼ç¤ºç没æè¿ä¸¤ä¸ªå段ï¼èèå°çå®çç¯å¢ä¸åºæ¬å
å«å°±å¨è¿éåå®å¼
	    private int code = 0;
			private String message = "OK";
	    //ç¨æ¥æ¨¡ä»¿Data
	    @SerializedName(value = "subjects")
	    private T data;
	}
2. åRetrofit2䏿 ·è¦å®ä¹æ¥å£ã
å¦ä¸ãè¿éä»
ä»
æ¯æGETçæ¥å£å¨demoéï¼POST, PUT, DELETE, QUERYç齿¯ä¸æ ·çãHttpResultéTçç±»åå°±æ¯æå®æ³ådataçå
·ä½ç±»åãå¯ä»¥ä½¿ç¨Stringï¼ JSONObjectï¼å®ä¹çå®ä½ççã
å¦å¤ææåé®é¢è®¿é®åæ°æ¯JSON对象æä¹å (Body Paramter JSON Object)ï¼è¿å ¶å®å°±æ¯å°ä½ çåæ°è®¾ç½®æä¸ä¸ªå·²ç»å®ä¹çå®ä½ï¼æä¹ç»åºä¸ä¸ªé¡¹ç®ä¸çæ¥å£ãä¸é¢çpostå°±æ¯è¿ç§æ¹å¼ãå ³äºè¯·æ±çRESTæ¹å¼æä¼å¨æç« å颿¾åºè¯¦ç»çåèï¼è¥ä½ ä¸çæè¯·åèè¿äºæç« ã
@GET("mock3")
Observable<HttpResult<MockBean>> getMock3();
@GET("mock1")
Observable<HttpResult<List<MockBean>>> getMock1();
@GET("mock4")
Observable<HttpResult<MockBean>> getMock4();
@GET("mock2")
Observable<HttpResult<MockBean>> getMock2();
3. 请æ±ç½ç»ã
ç´æ¥è°ç¨
public static MockApi mockApi() {
	return ServiceFactory.createService(MockApi.class);
}
使ç¨ä¸ä¸ªé»è®¤ç.compose(new DefaultTransformer<List<MockBean>>())å¯ä»¥é常æ¹ä¾¿å°è¿è¡è½¬åæäºéè¦çObservableãå¦ä¸ä»£ç ä¸é£æ ·è¿è¡äºçº¿ç¨ç转æ¢ï¼é误çå¤çå¨è¿ä¸ªtransformerï¼å¯ä»¥èªå®ä¹èªå·±çtransformerã
return observable
          .subscribeOn(Schedulers.io())
          .observeOn(Schedulers.newThread())
          .compose(ErrorTransformer.<T>getInstance())
          .observeOn(AndroidSchedulers.mainThread());
å¦å¤åå¤äºå¸¸ç¨çsubscriberï¼å
å«äºç½ç»è¿æ¥çé误å¤çï¼ä¾å¦é200ç¶æï¼å¦å¤æ¯æå¡ç«¯ï¼ä¸å¡ï¼é误çå¤çï¼é»è®¤æ¯å°é误ç¼ç åé误信æ¯å¨æ§å¶å°åææºä¸è¾åºã
æä¾çRxSubscriberå CommonScriberä¸çonNext()å¿
é¡»å®ç°ã
建议使ç¨RxLifecycle鲿¢ä½¿ç¨RxJavaå
åæ³é²ãå
¶å®æ¹é¢ä½¿ç¨åRxJavaä¸Retrofit2ç»åçä½¿ç¨æ¯ç¸åçï¼æä»¥å¾å°ç»ææ¨è¥æè¥è¦å¯¹æ°æ®è¿è¡å¤çä»ç¶æ¯é¾å¼è°ç¨ã
å ³äºé误å¤çæ¹é¢ä»ç»
主è¦ä½¿ç¨äºRxJavaä¸çonErrorResumeNextï¼éå°é误åå°é误éè¿ExceptionEngine.handleException(throwable)è¿è¡å¤çã
@Override
public Observable<T> call(Observable<HttpResult<T>> responseObservable) {
    return responseObservable.map(new Func1<HttpResult<T>, T>() {
        @Override
        public T call(HttpResult<T> httpResult) {
            // éè¿å¯¹è¿åç è¿è¡ä¸å¡å¤æå³å®æ¯è¿åéè¯¯è¿æ¯æ£å¸¸åæ°æ®
            if (httpResult.getCode() != ErrorType.SUCCESS) throw new ServerException(httpResult.getMessage(), httpResult.getCode());
            return httpResult.getData();
        }
    }).onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
        @Override
        public Observable<? extends T> call(Throwable throwable) {
            //ExceptionEngine为å¤çå¼å¸¸ç驱å¨å¨
            throwable.printStackTrace();
            return Observable.error(ExceptionEngine.handleException(throwable));
        }
    });
}
å ¶ä¸çApiExceptionå æ¬codeåé误ç详æ
public class ApiException extends Exception {
    // å¼å¸¸å¤çï¼ä¸ºé度ï¼ä¸å¿
è¦è®¾ç½®getteråsetter
    public int code;
    public String message;
    public ApiException(Throwable throwable, int code) {
        super(throwable);
        this.code = code;
    }
}
éç¹å¨äºä¸é¢è¿ä¸ªå¤çãä½ å¯ä»¥åå®ä¹èªå·±çä¸å¡ç¸å ³çé误ï¼ç®å常ç¨çé½å·²ç»æäºï¼èä¸ç¸å ³çé误大é¨åéè¿æ¥æ¶çæ°æ®ç´æ¥æ¾ç¤ºäºãè¥ä¸æ¯ç´æ¥æ¾ç¤ºçæ åµï¼ä½ å®å ¨å¯ä»¥å¨æä¾çsubscriberéå»å®ç°ã
public class ExceptionEngine {
    //对åºHTTPçç¶æç 
    private static final int UNAUTHORIZED = 401;
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;
    public static ApiException handleException(Throwable e){
        ApiException ex;
        if (e instanceof HttpException){             //HTTPé误
            HttpException httpException = (HttpException) e;
            ex = new ApiException(e, ErrorType.HTTP_ERROR);
            switch(httpException.code()){
                case UNAUTHORIZED:
                    ex.message = "å½å请æ±éè¦ç¨æ·éªè¯";
                    break;
                case FORBIDDEN:
                    ex.message = "æå¡å¨å·²ç»ç解请æ±ï¼ä½æ¯æç»æ§è¡å®";
                    break;
                case NOT_FOUND:
                    ex.message = "æå¡å¨å¼å¸¸ï¼è¯·ç¨ååè¯";
                    break;
                case REQUEST_TIMEOUT:
                    ex.message = "请æ±è¶
æ¶";
                    break;
                case GATEWAY_TIMEOUT:
                    ex.message = "ä½ä¸ºç½å
³æè
代çå·¥ä½çæå¡å¨å°è¯æ§è¡è¯·æ±æ¶ï¼æªè½åæ¶ä»ä¸æ¸¸æå¡å¨ï¼URIæ è¯åºçæå¡å¨ï¼ä¾å¦HTTPãFTPãLDAPï¼æè
è¾
婿å¡å¨ï¼ä¾å¦DNSï¼æ¶å°ååº";
                    break;
                case INTERNAL_SERVER_ERROR:
                    ex.message = "æå¡å¨éå°äºä¸ä¸ªæªæ¾é¢æçç¶åµï¼å¯¼è´äºå®æ æ³å®æå¯¹è¯·æ±çå¤ç";
                    break;
                case BAD_GATEWAY:
                    ex.message = "ä½ä¸ºç½å
³æè
代çå·¥ä½çæå¡å¨å°è¯æ§è¡è¯·æ±æ¶ï¼ä»ä¸æ¸¸æå¡å¨æ¥æ¶å°æ æçååº";
                    break;
                case SERVICE_UNAVAILABLE:
                    ex.message = "ç±äºä¸´æ¶çæå¡å¨ç»´æ¤æè
è¿è½½ï¼æå¡å¨å½åæ æ³å¤ç请æ±";
                    break;
                default:
                    ex.message = "ç½ç»é误";  //å
¶å®åè§ä¸ºç½ç»é误
                    break;
            }
            return ex;
        } else if (e instanceof ServerException){    //æå¡å¨è¿åçé误
            ServerException resultException = (ServerException) e;
            ex = new ApiException(resultException, resultException.code);
            ex.message = resultException.message;
            return ex;
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException){
            ex = new ApiException(e, ErrorType.PARSE_ERROR);
            ex.message = "è§£æé误";            //åè§ä¸ºè§£æé误
            return ex;
        }else if(e instanceof ConnectException || e instanceof SocketTimeoutException || e instanceof ConnectTimeoutException){
            ex = new ApiException(e, ErrorType.NETWORD_ERROR);
            ex.message = "è¿æ¥å¤±è´¥";  //åè§ä¸ºç½ç»é误
            return ex;
        }
        else {
            ex = new ApiException(e, ErrorType.UNKNOWN);
            ex.message = "æªç¥é误";          //æªç¥é误
            return ex;
        }
    }
}
å
³äºå¤çæå¡å¨å¨é误æ¶å°é误信æ¯ç´æ¥æ¾å¨dataåæ®µï¼å³dataåæ®µå¨ç»ææåå失败对åºçç±»åä¸å®ãå¤çæè·¯æ¯èªå®ä¹GsonConverterï¼å¯ä»¥æ¥çDemoéçMockDataActivityå»çä½¿ç¨æ¹æ³ï¼å
¶å®å°±ä¿®æ¹Retofit2åå§åä¼ å
¥çGsonConverterãå
³é®æ¯å¯¹äºCustomGsonResponseBodyConverterçä¿®æ¹ã
@Override
public T convert(ResponseBody value) throws IOException {
    String response = value.string();
    JsonElement jsonElement = jsonParser.parse(response);
    int parseCode = jsonElement.getAsJsonObject().get("code").getAsInt();
    //
    if (parseCode != ErrorType.SUCCESS) {
        value.close();
        String msg = jsonElement.getAsJsonObject().get("data").getAsString();
        throw new ServerException(msg, parseCode);
    } else {
        MediaType contentType = value.contentType();
        Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
        InputStream inputStream = new ByteArrayInputStream(response.getBytes());
        Reader reader = new InputStreamReader(inputStream, charset);
        JsonReader jsonReader = gson.newJsonReader(reader);
        try {
            return adapter.read(jsonReader);
        } finally {
            value.close();
        }
    }
}
è¿éå
è§£æcodeåæ®µåè¿è¡å¤æï¼æä»¥å¤çè¿ç§æå¡å¨è¿åçè¯ï¼æ¯éè¦å°ä¸é¢ç"code"å"data"æ¿æ¢æä½ æå¡ç«¯å
·ä½çåæ®µã
Update
2017-07-12
å¢å äºDagger 2.11(ä¾èµæ³¨å
¥)ç使ç¨ï¼éDagger2æ¹å¼æ¾å¨ä¸åçBranch noDagger2䏿¹ä¾¿ä¸ä½¿ç¨Dagger2ç¨æ·
2017-03-28
æ´æ°è¯´æææ¡£ï¼ä¿®æ£æ ¼å¼åéä½ï¼è§£å³å¨atomä¸tabé¿åº¦ä¸githubé¿åº¦ä¸å¯¹åºçæ¾ç¤ºé®é¢ã
2017-03-27
æ´æ°ææ¡£ï¼å¢å çè§é¢è¯´æï¼å¢å éè¯¯ä¿¡æ¯æ¾å¨dataåæ®µç说æã
2017-03-07
æ·»å å¤çéRESTæ¥å£å¨tokenå¤±ææ¶æcodeå¼å¸¸æ¶ï¼éè¯¯ä¿¡æ¯æ¾å¨dataåæ®µçè§£æåæ³å¤çã
 {
	code:-1
	data:"token失æ"
 }
{
	code:0
	data:{name:"xiaoming", age:23}
}
é对ä¸é¢çJSONé½è¦å¨åä¸ä¸ªæ¥å£éå¤çï¼è§£å³åæ³é½æ¯ä¸¤æ¬¡è§£æçåæ³ï¼ç¬¬ä¸æ¬¡åå°codeå¹¶ä¸å¤æï¼ä¸æ¯ææçå¼è¿è¡å¤çãææçå¼å¯æåè·¯å¤çãè¿ééç¨äºä¿®æ¹GsonConverterçåæ³ã
2016-12-26
è§£å³äºæ§è¡onCompleted()ä¹åæ§è¡onError()çé®é¢
if (!isUnsubscribed())
{
	unsubscribe();
}
2016-10-13
ä¿®æ£äºæå¡ç«¯code没æå¤çï¼è¿å为é误æ¶è®¤ä¸ºæ¯jsonå®ä½è§£æé®é¢ã
if (httpResult.getCode() != ErrorType.SUCCESS || httpResult.getCode() != ErrorType.SUCCESS)
Thanks
- Retrofitèªå®ä¹GsonConverterå¤ç请æ±é误å¼å¸¸å¤ç
- ä½ ççä¼ç¨Retrofit2å?Retrofit2å®å ¨æç¨
- Error handling in RxJava
- AndroidåºäºRetrofit2.0 å°è£ çè¶ å¥½ç¨çRetrofitClientå·¥å ·ç±»
- Retrofit2.0 忬¡å°è£ ï¼
- Retrofit + RxAndroid å®è·µæ»ç»
- RxJava ä¸ Retrofit ç»åçæä½³å®è·µ
- ä½ ççä¼ç¨Retrofit2å?Retrofit2å®å ¨æç¨
Contact Me
- Github: github.com/ysmintor
- Email: [email protected]
License
Copyright 2016 - 2017 YorkYu. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.