美文网首页
半天学会Retrofit的简单使用(基于RxJava)

半天学会Retrofit的简单使用(基于RxJava)

作者: reaiya | 来源:发表于2018-06-12 18:30 被阅读0次

    参考文章:https://www.jianshu.com/p/7b839b7c5884

    1. 准备

    安装依赖

        compile 'com.squareup.retrofit2:converter-gson:2.4.0'
        compile 'com.squareup.retrofit2:retrofit:2.4.0'
        compile 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
    

    注意:最好装最新的版本,adapter才提供对RxJava2的支持

    2. 使用

    创建RetrofitService接口,申明搜索数据的方法,请求方式是GET,传递的参数有“q”、“tag”、“start”和“count”

    public interface RetrofitService {
    
        // 根据条件搜索豆瓣书籍数据
        @GET("book/search")
        Observable<Book> getSearchBook(@Query("q") String name,@Query("tag") String tag,@Query("start") int start,@Query("count") int count);
        
    }
    

    创建实体类Book,安装GsonFormat插件,使用该插件根据搜索结果自动生成Book类

    public class Book {
    
        /**
         * count : 1
         * start : 0
         * total : 577
         * books : [{"rating":{"max":10,"numRaters":4746,"average":"8.6","min":0},"subtitle":"张竹坡批评第一奇书",
         * "author":["兰陵笑笑生"],"pubdate":"1991","tags":[{"count":2414,"name":"金瓶梅","title":"金瓶梅"},{"count":1314,
         * "name":"古典文学","title":"古典文学"},{"count":988,"name":"兰陵笑笑生","title":"兰陵笑笑生"},{"count":856,"name":"小说",
         * "title":"小说"},{"count":772,"name":"中国古典文学","title":"中国古典文学"},{"count":521,"name":"中国文学","title":"中国文学"},
         * {"count":432,"name":"古典","title":"古典"},{"count":413,"name":"中国","title":"中国"}],"origin_title":"(明)兰陵笑笑生",
         * "image":"https://img1.doubanio.com/view/subject/m/public/s10069398.jpg","binding":"","translator":[],
         * "catalog":"\n      ","pages":"","images":{"small":"https://img1.doubanio.com/view/subject/s/public/s10069398
         * .jpg","large":"https://img1.doubanio.com/lpic/s10069398.jpg","medium":"https://img1.doubanio
         * .com/view/subject/m/public/s10069398.jpg"},"alt":"https://book.douban.com/subject/1456692/","id":"1456692",
         * "publisher":"齐鲁出版社","isbn10":"7533300815","isbn13":"9787533300814","title":"金瓶梅","url":"https://api.douban
         * .com/v2/book/1456692","alt_title":"(明)兰陵笑笑生","author_intro":"","summary":"本书由王汝梅与李昭恂、于凤树校点。",
         * "series":{"id":"4279","title":"明代四大奇书"},"price":"268.00元"}]
         */
    
        private int count;
        private int start;
        private int total;
        private List<BooksBean> books;
    
        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 List<BooksBean> getBooks() {
            return books;
        }
    
        public void setBooks(List<BooksBean> books) {
            this.books = books;
        }
    
        public String toString(){
            return "搜索结果序列化";
        }
    
        public static class BooksBean {
            /**
             * rating : {"max":10,"numRaters":4746,"average":"8.6","min":0}
             * subtitle : 张竹坡批评第一奇书
             * author : ["兰陵笑笑生"]
             * pubdate : 1991
             * tags : [{"count":2414,"name":"金瓶梅","title":"金瓶梅"},{"count":1314,"name":"古典文学","title":"古典文学"},
             * {"count":988,"name":"兰陵笑笑生","title":"兰陵笑笑生"},{"count":856,"name":"小说","title":"小说"},{"count":772,
             * "name":"中国古典文学","title":"中国古典文学"},{"count":521,"name":"中国文学","title":"中国文学"},{"count":432,"name":"古典",
             * "title":"古典"},{"count":413,"name":"中国","title":"中国"}]
             * origin_title : (明)兰陵笑笑生
             * image : https://img1.doubanio.com/view/subject/m/public/s10069398.jpg
             * binding :
             * translator : []
             * catalog :
    
             * pages :
             * images : {"small":"https://img1.doubanio.com/view/subject/s/public/s10069398.jpg","large":"https://img1
             * .doubanio.com/lpic/s10069398.jpg","medium":"https://img1.doubanio.com/view/subject/m/public/s10069398.jpg"}
             * alt : https://book.douban.com/subject/1456692/
             * id : 1456692
             * publisher : 齐鲁出版社
             * isbn10 : 7533300815
             * isbn13 : 9787533300814
             * title : 金瓶梅
             * url : https://api.douban.com/v2/book/1456692
             * alt_title : (明)兰陵笑笑生
             * author_intro :
             * summary : 本书由王汝梅与李昭恂、于凤树校点。
             * series : {"id":"4279","title":"明代四大奇书"}
             * price : 268.00元
             */
    
            private RatingBean rating;
            private String subtitle;
            private String pubdate;
            private String origin_title;
            private String image;
            private String binding;
            private String catalog;
            private String pages;
            private ImagesBean images;
            private String alt;
            private String id;
            private String publisher;
            private String isbn10;
            private String isbn13;
            private String title;
            private String url;
            private String alt_title;
            private String author_intro;
            private String summary;
            private SeriesBean series;
            private String price;
            private List<String> author;
            private List<TagsBean> tags;
            private List<?> translator;
    
            public RatingBean getRating() {
                return rating;
            }
    
            public void setRating(RatingBean rating) {
                this.rating = rating;
            }
    
            public String getSubtitle() {
                return subtitle;
            }
    
            public void setSubtitle(String subtitle) {
                this.subtitle = subtitle;
            }
    
            public String getPubdate() {
                return pubdate;
            }
    
            public void setPubdate(String pubdate) {
                this.pubdate = pubdate;
            }
    
            public String getOrigin_title() {
                return origin_title;
            }
    
            public void setOrigin_title(String origin_title) {
                this.origin_title = origin_title;
            }
    
            public String getImage() {
                return image;
            }
    
            public void setImage(String image) {
                this.image = image;
            }
    
            public String getBinding() {
                return binding;
            }
    
            public void setBinding(String binding) {
                this.binding = binding;
            }
    
            public String getCatalog() {
                return catalog;
            }
    
            public void setCatalog(String catalog) {
                this.catalog = catalog;
            }
    
            public String getPages() {
                return pages;
            }
    
            public void setPages(String pages) {
                this.pages = pages;
            }
    
            public ImagesBean getImages() {
                return images;
            }
    
            public void setImages(ImagesBean images) {
                this.images = images;
            }
    
            public String getAlt() {
                return alt;
            }
    
            public void setAlt(String alt) {
                this.alt = alt;
            }
    
            public String getId() {
                return id;
            }
    
            public void setId(String id) {
                this.id = id;
            }
    
            public String getPublisher() {
                return publisher;
            }
    
            public void setPublisher(String publisher) {
                this.publisher = publisher;
            }
    
            public String getIsbn10() {
                return isbn10;
            }
    
            public void setIsbn10(String isbn10) {
                this.isbn10 = isbn10;
            }
    
            public String getIsbn13() {
                return isbn13;
            }
    
            public void setIsbn13(String isbn13) {
                this.isbn13 = isbn13;
            }
    
            public String getTitle() {
                return title;
            }
    
            public void setTitle(String title) {
                this.title = title;
            }
    
            public String getUrl() {
                return url;
            }
    
            public void setUrl(String url) {
                this.url = url;
            }
    
            public String getAlt_title() {
                return alt_title;
            }
    
            public void setAlt_title(String alt_title) {
                this.alt_title = alt_title;
            }
    
            public String getAuthor_intro() {
                return author_intro;
            }
    
            public void setAuthor_intro(String author_intro) {
                this.author_intro = author_intro;
            }
    
            public String getSummary() {
                return summary;
            }
    
            public void setSummary(String summary) {
                this.summary = summary;
            }
    
            public SeriesBean getSeries() {
                return series;
            }
    
            public void setSeries(SeriesBean series) {
                this.series = series;
            }
    
            public String getPrice() {
                return price;
            }
    
            public void setPrice(String price) {
                this.price = price;
            }
    
            public List<String> getAuthor() {
                return author;
            }
    
            public void setAuthor(List<String> author) {
                this.author = author;
            }
    
            public List<TagsBean> getTags() {
                return tags;
            }
    
            public void setTags(List<TagsBean> tags) {
                this.tags = tags;
            }
    
            public List<?> getTranslator() {
                return translator;
            }
    
            public void setTranslator(List<?> translator) {
                this.translator = translator;
            }
    
            public static class RatingBean {
                /**
                 * max : 10
                 * numRaters : 4746
                 * average : 8.6
                 * min : 0
                 */
    
                private int max;
                private int numRaters;
                private String average;
                private int min;
    
                public int getMax() {
                    return max;
                }
    
                public void setMax(int max) {
                    this.max = max;
                }
    
                public int getNumRaters() {
                    return numRaters;
                }
    
                public void setNumRaters(int numRaters) {
                    this.numRaters = numRaters;
                }
    
                public String getAverage() {
                    return average;
                }
    
                public void setAverage(String average) {
                    this.average = average;
                }
    
                public int getMin() {
                    return min;
                }
    
                public void setMin(int min) {
                    this.min = min;
                }
            }
    
            public static class ImagesBean {
                /**
                 * small : https://img1.doubanio.com/view/subject/s/public/s10069398.jpg
                 * large : https://img1.doubanio.com/lpic/s10069398.jpg
                 * medium : https://img1.doubanio.com/view/subject/m/public/s10069398.jpg
                 */
    
                private String small;
                private String large;
                private String medium;
    
                public String getSmall() {
                    return small;
                }
    
                public void setSmall(String small) {
                    this.small = small;
                }
    
                public String getLarge() {
                    return large;
                }
    
                public void setLarge(String large) {
                    this.large = large;
                }
    
                public String getMedium() {
                    return medium;
                }
    
                public void setMedium(String medium) {
                    this.medium = medium;
                }
            }
    
            public static class SeriesBean {
                /**
                 * id : 4279
                 * title : 明代四大奇书
                 */
    
                private String id;
                private String title;
    
                public String getId() {
                    return id;
                }
    
                public void setId(String id) {
                    this.id = id;
                }
    
                public String getTitle() {
                    return title;
                }
    
                public void setTitle(String title) {
                    this.title = title;
                }
            }
    
            public static class TagsBean {
                /**
                 * count : 2414
                 * name : 金瓶梅
                 * title : 金瓶梅
                 */
    
                private int count;
                private String name;
                private String title;
    
                public int getCount() {
                    return count;
                }
    
                public void setCount(int count) {
                    this.count = count;
                }
    
                public String getName() {
                    return name;
                }
    
                public void setName(String name) {
                    this.name = name;
                }
    
                public String getTitle() {
                    return title;
                }
    
                public void setTitle(String title) {
                    this.title = title;
                }
            }
        }
    }
    

    创建service

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("https://api.douban.com/v2/")
                    .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//支持RxJava
                    .build();
            service = retrofit.create(RetrofitService.class);
    

    绑定观察者和被观察者

                    Observable<Book> observable = service.getSearchBook(main2Edit1.getText().toString(), null, 0, 1)
                            .filter(new Predicate<Book>() {
                                @Override
                                public boolean test(@NonNull Book book) throws Exception {
                                    return book.getCount()>0;
                                }
                            })
                            .debounce(2, TimeUnit.SECONDS);
                    observable.observeOn(AndroidSchedulers.mainThread())
                            .doOnNext(new Consumer<Book>() {
                                @Override
                                public void accept(Book b) throws Exception {
                                    showProgress();
                                }
                            })
                            .subscribeOn(Schedulers.io())//请求数据的事件发生在io线程
                            .observeOn(AndroidSchedulers.mainThread())//请求完成后在主线程更显UI
                            .subscribe(new Consumer<Book>() {
                                @Override
                                public void accept(Book book) throws Exception {
                                    hideProgress();
                                    showResult(book);
                                }
                            });
    

    写于2018-4-7

    自定义拦截器,绑定公共参数

    public final class CommonParamsInterceptor implements Interceptor {
    
        private RetrofitClient retrofitClient;
        Map<String, String> mNetParas;
    
        public CommonParamsInterceptor(RetrofitClient retrofitClient, Map<String, String> mNetParas) {
            this.retrofitClient = retrofitClient;
            this.mNetParas = mNetParas;
        }
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
                request = processToBody(request);
    //        request = processToHeader(request);
            return chain.proceed(request);
        }
    
        private Request processToHeader(Request request) throws IOException {
            Request.Builder headerBuilder = request.newBuilder();
            Map<String, String> cloneHeaders = new HashMap<>(mNetParas);
            cloneHeaders.put(NetConfig.HEAD_TIMESTAMP, String.valueOf(TimeUtils.timesToServer(System.currentTimeMillis())));
            try {
                Map<String, String> headFinal = HeaderHMacSha256.toHMacSha256(cloneHeaders);
                for (Map.Entry<String, String> entry : headFinal.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        headerBuilder.addHeader(entry.getKey(), entry.getValue());
                    }
                }
                return headerBuilder.build();
            } catch (Exception e) {
                e.printStackTrace();
                throw new IOException("make header fail-->" + e.getMessage());
            }
        }
    
        private Request processToBody(Request request) {
            String method = request.method();
            if (method != null) {
                method = method.toLowerCase();
                if (method.contains("get")) {
                    request = processUrl(request);
                } else if (method.contains("post")
                        && request.body() != null
                        ) {
                    RequestBody requestBody = request.body();
                    if (requestBody != null) {
                        String subType = requestBody.contentType() != null ? requestBody.contentType().subtype() : null;
                        if (subType == null) {
                            requestBody = processFormDataRequestBody(requestBody);
                        } else {
                            boolean formPost = isFormPost(subType);
                            boolean jsonPost = isJsonPost(subType);
                            if (formPost) {
                                requestBody = processFormDataRequestBody(requestBody);
                            } else if (jsonPost) {
                                requestBody = processApplicationJsonRequestBody(requestBody);
                            }
                        }
    
                        if (requestBody != null) {
                            Request.Builder requestBuilder = request.newBuilder();
                            request = requestBuilder
                                    .post(requestBody)
                                    .build();
                        }
                    }
    
                }
            }
            return request;
        }
    
        private Request processUrl(Request request) {
            HttpUrl.Builder urlBuilder = request.url().newBuilder();
            for (Map.Entry<String, String> entry : mNetParas.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                urlBuilder.addQueryParameter(key, value);
            }
            request = request.newBuilder().url(urlBuilder.build()).build();
            return request;
        }
    
    
        private RequestBody processFormDataRequestBody(RequestBody requestBody) {
            FormBody.Builder formBuilder = new FormBody.Builder();
            for (Map.Entry<String, String> entry : mNetParas.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                formBuilder.add(key, value);
            }
            RequestBody formBody = formBuilder.build();
            String postBodyString = bodyToString(requestBody);
            postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);
            MediaType contentType = requestBody.contentType();
            if (contentType == null) {
                contentType = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
            }
            return RequestBody.create(contentType, postBodyString);
        }
    
        private RequestBody processApplicationJsonRequestBody(RequestBody requestBody) {
            String customReq = bodyToString(requestBody);
            try {
                JSONObject obj = new JSONObject(customReq);
                for (Map.Entry<String, String> entry : mNetParas.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    obj.put(key, value);
                }
                return RequestBody.create(requestBody.contentType(), obj.toString());
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private String bodyToString(final RequestBody request) {
            try {
                final RequestBody copy = request;
                final Buffer buffer = new Buffer();
                if (copy != null)
                    copy.writeTo(buffer);
                else
                    return "";
                return buffer.readUtf8();
            } catch (final IOException e) {
                return "did not work";
            }
        }
    
        private boolean isJsonPost(String subType) {
            return subType.contains("json");
        }
    
        private boolean isFormPost(String subType) {
            return subType.contains("form");
        }
    }
    

    同样,还可以在拦截器里做打印日志、统一错误处理等操作。

    更新于2018-6-11

    我们经常会有统一处理返回结果的需求,比如我们接口的返回结果的格式是这样的:

    code:200,
    message:"success",
    data:{}
    

    我们需要在返回结果前处理code,确认结果正常后再将data数据返回给业务层,那么我们可以这样做:

    1. 自定义一个Convert.Factory,替换掉以上.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))代码中的GsonConverterFactory
    2. 我们还可以替换掉以上.addCallAdapterFactory(RxJava2CallAdapterFactory.create())代码中的RxJava2CallAdapterFactory,实现RxJava并且加上我们的处理逻辑

    自定义的BodyConverterFactory:

    public final class BodyConverterFactory extends Converter.Factory {
        /**
         * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
         * decoding from JSON (when no charset is specified by a header) will use UTF-8.
         *
         * @param deviceSession
         */
        public static BodyConverterFactory create(Map<String, String> deviceSession, Gson gson) {
    
            return create(gson, deviceSession);
        }
    
        /**
         * Create an instance using {@code gson} for conversion. Encoding to JSON and
         * decoding from JSON (when no charset is specified by a header) will use UTF-8.
         */
        @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
        public static MobooConverterFactory create(Gson gson, Map<String, String> deviceSession) {
            if (gson == null) throw new NullPointerException("gson == null");
            return new MobooConverterFactory(gson, deviceSession);
        }
    
        private final Gson gson;
        
        private BodyConverterFactory(Gson gson, Map<String, String> deviceSession) {
            this.gson = gson;
        }
        
        @Override
        @SuppressWarnings("unchecked")//忽略转换错误
        public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                              Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
            for (Annotation annotation : methodAnnotations) {
                if (annotation instanceof WithoutRequestConverter) {
                    return new GsonRequestWithoutConverter(this.gson, adapter);
                }
            }
            TypeAdapter adapter = this.gson.getAdapter(TypeToken.get(type));
            return new GsonRequestBodyConverter(this.gson, adapter);
        }
    
        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                                Retrofit retrofit) {
            for (Annotation annotation : annotations) {
                if (annotation instanceof WithoutResponseConverter) {
                    return new GsonResponseWithoutConverter<>(gson, adapter);
                } 
            }
            TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
            return new GsonResponseBodyConverter<>(gson, adapter);
        }
    }
    
    GsonRequestBodyConverter GsonResponseBodyConverter

    可以看到,在对RequestBody和ResponseBody转换之前,我们先判断了在方法注解里面有没有without注解,这两个注解是我们自定义的注解,里面没有任何逻辑,只需要在使用时加上就可以了,加上这两个注解后表示我们不需要对RequestBody和ResponseBody进行转换,常用于非系统内接口调用

    更新于2018-7-5

    相关文章

      网友评论

          本文标题:半天学会Retrofit的简单使用(基于RxJava)

          本文链接:https://www.haomeiwen.com/subject/lcjshftx.html