Android网络请求框架(三) Retrofit配合RxJava

大家好,好久没有更新了,今天给大家介绍一下目前火了很久很久的框架,Retrofit加R xJava配合使用


xJava配合使用)

介绍

retrofit是okhttp的加强版,底层封装了Okhttp。准确来说,Retrofit是一个RESTful的http网络请求框架的封装。因为网络请求工作本质上是由okhttp来完成,而Retrofit负责网络请求接口的封装。

优点

  • 超级解耦

  • 支持同步、异步、Rxjava

  • 可以配置不同反序列化工具类来解析不同的数据,如json、xml

  • 请求速度快,使用方便灵活简洁

使用必要操作

添加依赖:


    //Retrofit:
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'


    //glide4:		//用于图片处理
    implementation 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

    //RxJava:
    implementation "io.reactivex.rxjava2:rxjava:2.1.3" // 必要rxjava2依赖
    implementation "io.reactivex.rxjava2:rxandroid:2.0.1" // 必要rxandrroid依赖,切线程时需要用到
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' // 必要依赖,和Retrofit结合必须用到,下面会提到

    /**
     *      日志拦截器
     */
    implementation 'com.squareup.okhttp3:logging-interceptor:3.3.1'

请求方法,请求头,请求参数表格介绍

请求方法:

注解 说明
@GET get请求
@POST post请求
@PUT put请求
@DELETE delete请求
@PATCH patch请求
@HEAD head请求 : 用于更新局部资源
@OPTIONS options请求
@HTTP put请求通过注解,可以替换以上所有的注解,它拥有三个属性:method、path、hasBody

本篇只给大家讲解常用的请求方法@GET,@POST和@HTTP请求.

请求头:

请求头注解 说明
@Headers 用于添加固定请求头,可以同时添加多个,通过该注解的请求头不会相互覆盖,而是共同存在
@Header 作为方法的参数传入,用于添加不固定的header,它会更新已有请求头

本篇不给大家讲解请求头,请求头可以通过代码来写入,因为太多注解容易搞混,这里也不建议大家使用注解的方法添加请求头.

请求参数:

请求参数 说明
@Body 多用于POST请求发送非表达数据,根据转换方式将实例对象转化为对应字符串传递参数,比如使用Post发送Json数据,添加GsonConverterFactory则是将body转化为json字符串进行传递
@Filed 用于POST请求 需要结合@FromUrlCoded以表单形式传递参数
@FiledMap 用于POST请求中的表单字段,传递多个参数,需要结合@FromUrlEncoded使用
@Part 用于POST请求,与@multipart配合使用,多用于上传单个文件
@PartMap 用于POST请求,与@multipart配合使用,多用于上传多个文件
@Path Url中的占位符
@Query 用于Get请求中的参数
@QueryMap 与Query类似,用于不确定表单参数
@Url 指定请求路径

请求和响应格式:

请求和响应格式(标记)注解 说明
@FromUrlEncoded @FiledMap 和 @Filed 使用的时候必须添加
@Multipart @PartMap 和 @Part 使用的时候必须添加
@Streaming 表示响应用字节流的形式返回,如果没有使用注解,默认会把数据全部载入到内存中,该注解在下载大文件时特别有用

@GET请求:

先定义一个接口:

public interface ApiServer {

	//定义要请求的接口前半段,注意:这里必须以/结尾!!!
    public static String BaseUri = "https://gank.io/api/data/%E7%A6%8F%E5%88%A9/";

	 /**
     *      通过调用getMeiNvBen()使用@Path注解,将传过来的参数设置给@GET()
     *      实现GET的传递 
     */
 	@GET("{number}/{index}")
    Observable<MeiNvBean> getMeiNvBean(@Path("number")String number, @Path("index")String index);

	/**
     *
     * @param method    网络请求的方法(区分大小写)
     * @param path      网络请求地址路径
     * @param hasBody  是否有请求体
     * @return
     */
    @HTTP(method = "GET",path = "{number}/{index}" ,hasBody = false)
    Observable<MeiNvBean> getHttpMeiNvBean(@Path("number")String number, @Path("index")String index);

}

我的MeiNvBean类是通过Postman软件来请求数据,然后通过GsonFromat来得到对应的实体类:

在这里插入图片描述

获取MeiNvBean 实体类:

package demo.ht.com.volley.bean;

import java.util.List;

public class MeiNvBean {

    /**
     * error : false
     * results : [{"_id":"5be14edb9d21223dd50660f8","createdAt":"2018-11-06T08:20:43.656Z","desc":"2018-11-06","publishedAt":"2018-11-06T00:00:00.0Z","source":"web","type":"福利","url":"https://img.lijinshan.site/images/8733844e0b954e7e8e29102cefa32dbf","used":true,"who":"lijinshanmx"},{"_id":"5bcd71979d21220315c663fc","createdAt":"2018-10-22T06:43:35.440Z","desc":"2018-10-22","publishedAt":"2018-10-22T00:00:00.0Z","source":"web","type":"福利","url":"https://img.lijinshan.site/images/0bc3ed0deda74674b45bebb140bb5928","used":true,"who":"lijinshanmx"},{"_id":"5bc434ac9d212279160c4c9e","createdAt":"2018-10-15T06:33:16.497Z","desc":"2018-10-15","publishedAt":"2018-10-15T00:00:00.0Z","source":"web","type":"福利","url":"https://img.lijinshan.site/images/1635f0ffd94f40ff8058c2c4ff652e61","used":true,"who":"lijinshanmx"},{"_id":"5bbb0de09d21226111b86f1c","createdAt":"2018-10-08T07:57:20.978Z","desc":"2018-10-08","publishedAt":"2018-10-08T00:00:00.0Z","source":"web","type":"福利","url":"https://img.lijinshan.site/images/e930b75f48ae40b0a23f827e619d76a3","used":true,"who":"lijinshanmx"},{"_id":"5ba206ec9d2122610aba3440","createdAt":"2018-09-19T08:21:00.295Z","desc":"2018-09-19","publishedAt":"2018-09-19T00:00:00.0Z","source":"web","type":"福利","url":"https://img.lijinshan.site/images/d19c8feacc884e18898034c79e6e1a9d","used":true,"who":"lijinshanmx"},{"_id":"5b9771a29d212206c1b383d0","createdAt":"2018-09-11T07:41:22.491Z","desc":"2018-09-11","publishedAt":"2018-09-11T00:00:00.0Z","source":"web","type":"福利","url":"https://img.lijinshan.site/images/38ddf2ca672345889343b5748ffce78d","used":true,"who":"lijinshanmx"},{"_id":"5b830bba9d2122031f86ee51","createdAt":"2018-08-27T04:21:14.703Z","desc":"2018-08-27","publishedAt":"2018-08-28T00:00:00.0Z","source":"web","type":"福利","url":"https://img.lijinshan.site/images/a8aa7df22298413e9ca37c7a634e3425","used":true,"who":"lijinshanmx"},{"_id":"5b7b836c9d212201e982de6e","createdAt":"2018-08-21T11:13:48.989Z","desc":"2018-08-21","publishedAt":"2018-08-21T00:00:00.0Z","source":"web","type":"福利","url":"https://ws1.sinaimg.cn/large/0065oQSqly1fuh5fsvlqcj30sg10onjk.jpg","used":true,"who":"lijinshanmx"}]
     */

    private boolean error;
    private List<ResultsBean> results;

    @Override
    public String toString() {
        return "MeiNvBean{" +
                "error=" + error +
                ", results=" + results +
                '}';
    }

    public boolean isError() {
        return error;
    }

    public void setError(boolean error) {
        this.error = error;
    }

    public List<ResultsBean> getResults() {
        return results;
    }

    public void setResults(List<ResultsBean> results) {
        this.results = results;
    }

    public static class ResultsBean {
        /**
         * _id : 5be14edb9d21223dd50660f8
         * createdAt : 2018-11-06T08:20:43.656Z
         * desc : 2018-11-06
         * publishedAt : 2018-11-06T00:00:00.0Z
         * source : web
         * type : 福利
         * url : https://img.lijinshan.site/images/8733844e0b954e7e8e29102cefa32dbf
         * used : true
         * who : lijinshanmx
         */

        private String _id;
        private String createdAt;
        private String desc;
        private String publishedAt;
        private String source;
        private String type;
        private String url;
        private boolean used;
        private String who;

        @Override
        public String toString() {
            return "ResultsBean{" +
                    "_id='" + _id + '\'' +
                    ", createdAt='" + createdAt + '\'' +
                    ", desc='" + desc + '\'' +
                    ", publishedAt='" + publishedAt + '\'' +
                    ", source='" + source + '\'' +
                    ", type='" + type + '\'' +
                    ", url='" + url + '\'' +
                    ", used=" + used +
                    ", who='" + who + '\'' +
                    '}';
        }

        public String get_id() {
            return _id;
        }

        public void set_id(String _id) {
            this._id = _id;
        }

        public String getCreatedAt() {
            return createdAt;
        }

        public void setCreatedAt(String createdAt) {
            this.createdAt = createdAt;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        public String getPublishedAt() {
            return publishedAt;
        }

        public void setPublishedAt(String publishedAt) {
            this.publishedAt = publishedAt;
        }

        public String getSource() {
            return source;
        }

        public void setSource(String source) {
            this.source = source;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public boolean isUsed() {
            return used;
        }

        public void setUsed(boolean used) {
            this.used = used;
        }

        public String getWho() {
            return who;
        }

        public void setWho(String who) {
            this.who = who;
        }
    }
}

使用最原始未封装GET请求数据:

Retrofit apiServer = new Retrofit.Builder().
                addCallAdapterFactory(RxJava2CallAdapterFactory.create()).
                addConverterFactory(GsonConverterFactory.create())
                .baseUrl(ApiServer.BaseUri)
                .build();

//        apiServer.create(ApiServer.class).getHttpMeiNvBean("8","1")
        apiServer.create(ApiServer.class).getMeiNvBean("8", "1")
                .subscribeOn(Schedulers.io())//IO线程
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<MeiNvBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(MeiNvBean meiNvBean) {
                        mTv.setText(meiNvBean.toString());
                        Log.i("szjonNex", meiNvBean.toString());
                    }

                    @Override
                    public void onError(Throwable e) {
                        mTv.setText("请求错误:" + e.getMessage());
                        Log.i("onError", e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

来康康Log吧:
在这里插入图片描述

@POST请求

还是先定义接口来实现请求接口的声明:


public interface ApiServer {
	//定义要请求的接口前半段,注意:这里必须以/结尾!!!
	public static String GuoChuangYun_BaseUri = "http://hn216.api.yesapi.cn/";

	 /**
     *
     * @param FormUrlEncoded   通过FieldMap上传必须加@FormUrlEncoded注解 表示声明表单上传
     * @return
     */
    @FormUrlEncoded
    @POST("?s=App.User.Search")
    Observable<GuoChuangYunBean> getPOSTGuoCHuangYunBean(@FieldMap Map<String ,String > map);

	 /**
     *
     * @param body  POST请求体上传       FormBody app_key = new FormBody.Builder()
     *                                  .add("key", "valye")
     *                                  .build();
     * @return
     */
    @POST("?s=App.User.Search")
    Observable<GuoChuangYunBean> getPOSTBodyGuoCHuangYunBean(@Body RequestBody body);
}

通过Postman请求POST接口,获取参数,在通过GsonFromat获取实体类;

在这里插入图片描述

获取GuoChuangYunBean实体类:

package demo.ht.com.volley.bean;

import java.util.List;

public class GuoChuangYunBean {

    /**
     * ret : 200
     * data : {"err_code":0,"err_msg":"","users":[]}
     * msg : V3.1.0 YesApi App.User.Search
     */

    private int ret;
    private DataBean data;
    private String msg;

    @Override
    public String toString() {
        return "GuoChuangYunBean{" +
                "ret=" + ret +
                ", data=" + data +
                ", msg='" + msg + '\'' +
                '}';
    }

    public int getRet() {
        return ret;
    }

    public void setRet(int ret) {
        this.ret = ret;
    }

    public DataBean getData() {
        return data;
    }

    public void setData(DataBean data) {
        this.data = data;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public static class DataBean {
        /**
         * err_code : 0
         * err_msg :
         * users : []
         */

        private int err_code;
        private String err_msg;
        private List<?> users;

        @Override
        public String toString() {
            return "DataBean{" +
                    "err_code=" + err_code +
                    ", err_msg='" + err_msg + '\'' +
                    ", users=" + users +
                    '}';
        }

        public int getErr_code() {
            return err_code;
        }

        public void setErr_code(int err_code) {
            this.err_code = err_code;
        }

        public String getErr_msg() {
            return err_msg;
        }

        public void setErr_msg(String err_msg) {
            this.err_msg = err_msg;
        }

        public List<?> getUsers() {
            return users;
        }

        public void setUsers(List<?> users) {
            this.users = users;
        }
    }
}

使用最原始的请求方式请求POST数据:

HashMap<String, String> stringHashMap = new HashMap<>();
        stringHashMap.put("app_key", "74D2E724FE2B69EF7EA3F38E9400CF71");

        FormBody app_key = new FormBody.Builder()
                .add("app_key", "74D2E724FE2B69EF7EA3F38E9400CF71")
                .build();

Retrofit apiServer = new Retrofit.Builder().
                addCallAdapterFactory(RxJava2CallAdapterFactory.create()).
                addConverterFactory(GsonConverterFactory.create())
                .baseUrl(ApiServer.GuoChuangYun_BaseUri)
                .build();


        apiServer.create(ApiServer.class)
                .getPOSTBodyGuoCHuangYunBean(app_key)//@Body注解上传 
//                .getPOSTGuoCHuangYunBean(stringHashMap)//@FormUrlEncoded配合@FieldMap
                .subscribeOn(Schedulers.io())//IO线程
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<GuoChuangYunBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(GuoChuangYunBean guoChuangYunBean) {
                      
                        Log.i("szjPOSTonNext","\n"+guoChuangYunBean.toString());
                        mTv.setText("POST接口:\n" + guoChuangYunBean.toString());
                    }

                    @Override
                    public void onError(Throwable e) {

                        mTv.setText("POST接口请求错误:\n" + e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

来康康Log吧:

在这里插入图片描述

打开本地相册选取图片上传图片

打开本地相册 注意申请动态权限

		//打开本地相册
        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        intent.setType("image/png");
        intent.setAction(Intent.ACTION_PICK);
        startActivityForResult(intent, REQUEST_PICTURE_CHOOSE);

重写onActivityResult()方法,获取选取的图片路径,并上传图片

	 @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_PICTURE_CHOOSE) {
            /**
             *  先获取系统返回的图片路径
             *  然后将图片上传,因为这里接口有问题,所以上传不成功!
             */
            Uri selectedImage = data.getData(); //获取系统返回的照片的Uri
            String[] filePathColumn = {MediaStore.Images.Media.DATA};
            Cursor cursor = getContentResolver().query(selectedImage,
                    filePathColumn, null, null, null);//从系统表中查询指定Uri对应的照片
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String path = cursor.getString(columnIndex);  //获取照片路径

            Log.i("szjpath", "\t\t" + path);
			//上传图片
            initUpdata(path);
        }
    }

定义接口,设置请求参数:

public interface ApiServer {

		public static String GuoChuangYun_BaseUri = "http://hn216.api.yesapi.cn/";
		
	/**
     *
     * @param body  上传图片
     * @return
     */
	//    @Multipart    注意 : @Multipart 是配合@Part或@PartMap使用的,单独不能使用!!!!!!!
    @POST("?s=App.CDN.UploadImg")
    Observable<ImageBean> getImageBean( @Body RequestBody file);

    /**\
     *
     * @param body  上传的app_key
     * @param file  上传的单张图片
     * @return
     */
    @Multipart
    @POST("?s=App.CDN.UploadImg")
    Observable<ImageBean> uploadFile(@Part("app_key") RequestBody body, @Part MultipartBody.Part file);

}

通过Postman获取数据,并通过GsonFragment获取实体类,这里就不重复写了,和上面步骤一样:

File file = new File(path);

//方法一:
        RequestBody requestBody = new MultipartBody.Builder().
                setType(MultipartBody.FORM)
                .addFormDataPart("app_key", "74D2E724FE2B69EF7EA3F38E9400CF71")
                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/png"), file))
                .build();
                
//方法二:
RequestBody fileRQ = RequestBody.create(MediaType.parse("image/png"), file);
        MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), fileRQ);
        RequestBody fb =RequestBody.create(MediaType.parse("text/plain"), "74D2E724FE2B69EF7EA3F38E9400CF71");


Retrofit apiServer = new Retrofit.Builder().
                addCallAdapterFactory(RxJava2CallAdapterFactory.create()).
                addConverterFactory(GsonConverterFactory.create())
                .baseUrl(ApiServer.GuoChuangYun_BaseUri)
                .build();
        apiServer.create(ApiServer.class)
//                .getImageBean(requestBody)    //@Body 图片+参数 同时上传
                .uploadFile(requestBody,part)   //@Multipart 配合 @Part 单张图片 和单个参数上传
                .subscribeOn(Schedulers.io())//IO线程
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ImageBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(ImageBean imageBean) {
                        String url = imageBean.getData().getUrl();
                        Glide.with(RetrofitActivity.this)
                                .load(url)
                                .apply(new RequestOptions().placeholder(R.mipmap.ic_launcher))
                                .into(mImage);
                        mTv.setText("图片上传成功:\n" + imageBean.toString());
                        Log.i("szjOnNext", imageBean.toString());
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.i("onError", e.getMessage());
                        mTv.setText("图片上传失败:\n" + e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

我打开相册上传一张我健身的照片,来康康效果吧:

在这里插入图片描述

哈哈哈哈哈,献丑了献丑了,还怪不好意思的,羞羞QvQ

@Url使用:

这里拿get接口举例:

public interface ApiServer {
	 @GET
    Observable<MeiNvBean> getUrlMeiNvBean(@Url String url);

}


@Url特别简单,就是传一个完整的接口,通常用于GET请求,没什么难度,就不详细讲解了
Retrofit apiServer = new Retrofit.Builder().
                addCallAdapterFactory(RxJava2CallAdapterFactory.create()).
                addConverterFactory(GsonConverterFactory.create())
                .baseUrl(ApiServer.BaseUri)
                .build();

        apiServer.create(ApiServer.class).getUrlMeiNvBean(ApiServer.BaseUri+"8/1")
                .subscribeOn(Schedulers.io())//IO线程
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<MeiNvBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(MeiNvBean meiNvBean) {
                        mTv.setText(meiNvBean.toString());
                        Log.i("szjonNex", meiNvBean.toString());
                    }

                    @Override
                    public void onError(Throwable e) {
                        mTv.setText("请求错误:" + e.getMessage());
                        Log.i("onError", e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

康康所有的效果吧:

在这里插入图片描述
本篇重复代码比较多,下一篇给大家吧Retrofit封装起来,有想看的同学可以点击查看

Git链接: langyangyang.

写一篇博客实在是太累了,而且还容易写错误导大家,如果有大佬看到有错误的地方,一定请在评论区留言,谢谢大家观看~

猜你喜欢

转载自blog.csdn.net/weixin_44819566/article/details/107488575