zoukankan      html  css  js  c++  java
  • Android 网络框架 Retrofit2

    概述

    Retrofit是一个OkHttp网络请求框架的封装库,Retrofit通过注解配置网络参数,可以按照我们的规则去构造实际的HTTP请求,能够灵活设置URL、头部、请求体、返回值等,是目前最优雅的一个网络框架。

    添加依赖

    implementation 'com.squareup.retrofit2:retrofit:2.2.0'
    
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'//添加对RxJava的支持
    implementation 'com.squareup.retrofit2:converter-gson:2.1.0' //添加Json数据的支持
    
    <uses-permission android:name="android.permission.INTERNET"/>//网络请求必要的权限

    Retrofit基本使用三部曲

    创建实例

     Retrofit retrofit = new Retrofit.Builder()
              .baseUrl("http://id1.option****.cc:***1/")//Retrofit2 的baseUlr 必须以 /(斜线) 结束
              .build();
    RetrofitService service = retrofit.create(RetrofitService.class);//创建接口的代理对象

    定义接口

    public interface RetrofitService {
        
        @GET("/pursuit/getPursuitInfo")
        Call<ResponseBody> getBlog(@Query("id") int id);
    
        @GET("/pursuit/getPursuitInfo/{id}")
        Call<ResponseBody> getBlog2(@Path("id") String id);
        
    }

    创建 同步/异步 回调 

    //异步的回调
    Call<ResponseBody> call = service.getBlog(123);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
            try {
                Log.i("返回信息",response.body().string()+"");//打印返回信息
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            t.printStackTrace();//错误信息
        }
    });
    
    /*同步的回调,如果不是在一个Activity或者一个Fragment中去执行,那么也就意味着,你可以不需要开启子线程去执行网络请求。如果是在主线程,就必须开启子线程来进行同步请求
    使用call.execute()同步请求,只能调用一次。如果要多次使用这个方法,需要 call.clone()重新生成新的Call实例*/
    
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                retrofit2.Response<ResponseBody> response = call.execute();
                response.body();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

    HTTP协议中的常用请求

    GET: 请求指定的页面信息,以?分割URL和传输数据,参数之间以&相连,最多只能是1024字节,并返回实体主体,该操作用于获取信息而非修改信息

    HEAD: 只请求页面的首部。

    POST: POST表示可能修改变服务器上的资源的请求,.POST的安全性要比GET的安全性高

    PUT: 从客户端向服务器传送的数据取代指定文档的内容。

    Retrofit注解的重点详解

    注解汇总

    需要理解并灵活搭配使用

    基本请求

    Responsebody是Retrofit网络请求回来的原始数据类。get方式可以在url后面串联

    @Path注解用于替换请求参数,@Query注解相当于url后面的串联,他们可以同时使用

    请看下面第三种表达式:

    @GET("/pursuit/getPursuitInfo?id=123")
    Call<ResponseBody>  getCall();
    
    @POST("/pursuit/getPursuitInfo")
    Call<ResponseBody> getBlog(@Query("id") int id);
    
    @GET("/pursuit/getPursuitInfo/{id}")
    Call<ResponseBody> getBlog2(@Path("id") String id);

    自定义请求

    需要用到@HTTP注解

    /* method:网络请求的方法,注意大小写
     * path:网络请求地址路径
     * hasBody:是否有请求体
     * {id} 表示是一个变量*/
    @HTTP(method = "GET", path = "/pursuit/getPursuitInfo/{id}", hasBody = false)
    Call<ResponseBody> getCall(@Path("id") int id);

    请求体非Form表单

    @Body是Post方式提交非Form的表单

    @POST("/pursuit/getPursuitInfo")
    Observable<String> getPursuitInfo(@Body User user);

    请求体是Form表单

    如果请求的Form表单,需要用@FormUrlEncoded标注,@Field注解用于表单字段,它和@FieldMap都需要@FormUrlEncoded配合使用

    @Field和@Query都是表单字段,@FieldMap和@Query都是批量增加表单的提交域。区别如上图,一个拼接在URL上适用于get方式,一个体现在请求体上试用于post方式,区分好使用场景。

    @POST("/pursuit/getPursuitInfo") 
    @FormUrlEncoded
    Call
    <ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);

    设置请求头

    两种请求头的,@Header用于添加不固定的请求头,作用于方法的参数。@Headers用于添加固定的请求头,作用于方法

    @Headers("Authorization: authorization")
    @GET("/pursuit/getPursuitInfo")
    Call<ResponseBody> getUser();
    
    @GET("/pursuit/getPursuitInfo")
    Call<ResponseBody> getUser(@Header("Authorization") String authorization);

    动态替换URL

    用@Url替换已经设置的baseUrl

    @GET
    public Call<ResponseBody> profilePicture(@Url String url);

    图片上传

    @POST("user/updateAvatar.do")
    @Multipart
    Call<ResponseBody> upload(@Part("upload1"; filename="image1.jpg"") RequestBody imgs );

    文件上传

    发送form-encoded的数据,用于有文件上传的场景时要用 @Multipart 注解,@Part和@PartMap适用于有文件上传的情况

    @POST("mobile/upload")
    @Multipart
    Call<ResponseBody> upload(@Part MultipartBody.Part file);

    文件上传相关阅读

     轻松实现多文件/图片上传/Json字符串/表单

     Retrofit上传文件的参数设置

    ※以上就是所有参数注解的用法,需要实践灵活试用。

    Retrofit与Gson

    添加对gson的支持

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://id1.option****.cc:***1/")//Retrofit2 的baseUlr 必须以 /(斜线) 结束
            .addConverterFactory(GsonConverterFactory.create())//添加对gson的支持
            .build();

    建立接口,返回Bean

    public interface PostRoute {
       @Headers({"Content-Type: application/json","Accept: application/json"})//需要添加头
       @POST("api/FlyRoute/Add")
       Call<FlyRouteBean> postFlyRoute(@Body RequestBody route);//传入的参数为RequestBody
    }

    将Bean转换成json字符串

    FlyRouteBean flyRouteBean=new FlyRouteBean();
            flyRouteBean=initdata(flyRouteBean);//根据Bean类初始化一个需要提交的数据类
            Gson gson=new Gson();
            String route= gson.toJson(flyRouteBean);//通过Gson将Bean转化为Json字符串形式 

    提交json数据

    RequestBody body=RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),route); //将json转换成RequestBody请求体
    Call<FlyRouteBean> call=postRoute.postFlyRoute(body);//提交

    Retrifit与RxJava

    引入RxJava

    compile 'io.reactivex.rxjava2:rxjava:2.1.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

     添加对RxJava的支持

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://id1.option****.cc:***1/")//Retrofit2 的baseUlr 必须以 /(斜线) 结束
            .addConverterFactory(GsonConverterFactory.create())//添加对gson的支持                                       
            .client(client)//添加okhttp的支持
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加对RxJava的支持
            .build();

    连接超时与开启okhttp的日志打印

        private static final OkHttpClient client = new OkHttpClient.Builder().
                addInterceptor(new HttpLoggingInterceptor().//开启日志信息
                setLevel(HttpLoggingInterceptor.Level.BODY)).
                connectTimeout(600, TimeUnit.SECONDS).//连接超时
                readTimeout(600, TimeUnit.SECONDS).//读取超时
                writeTimeout(600, TimeUnit.SECONDS).build();//写入超时

    建立接口,返回Observable被观察者

    @GET("top250")
    Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);

    建立观察者

    Observable<String> observable =service.getTopMovie(0, 10)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<ResponseBody>() {
            @Override
            public void onSubscribe(Disposable d) {
    
            }
    
            @Override
            public void onNext(ResponseBody responseBody) {
    
            }
    
            @Override
            public void onError(Throwable e) {
    
            }
    
            @Override
            public void onComplete() {
    
            }
        });

    Retrofit的简单封装

    retrofit工具类

    public class WebManager {
        private static WebManager webManager;
        private RetrofitService retrofitService;
        public WebManager(Context context) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(StaticConstant.HOST_PORT)//地址
                    .addConverterFactory(GsonConverterFactory.create())//添加gson支持
                    .client(client)//设置okhttp连接
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加RxJava的支持
                    .build();
            retrofitService = retrofit.create(RetrofitService.class);
        }
        private static final OkHttpClient client = new OkHttpClient.Builder().
                addInterceptor(new HttpLoggingInterceptor().//开启日志信息
                setLevel(HttpLoggingInterceptor.Level.BODY)).
                connectTimeout(600, TimeUnit.SECONDS).//连接超时
                readTimeout(600, TimeUnit.SECONDS).//读取超时
                writeTimeout(600, TimeUnit.SECONDS).build();//写入超时
        //获取单例
        public static WebManager getInstance(Context context){
            if(webManager == null){
                webManager = new WebManager(context);
            }
            return webManager;
        }
        //上传xx信息,使用@Field注解
        public void postInfoField(Callback<ResponseBody> callback, String str){
            retrofitService.getWarrant("queryApplicationForm",null,str)
                    .enqueue(callback);
        }
        //上传xx信息,使用@FieldMap注解
        public void postInfoFieldMap(Callback<ResponseBody> callback, String num,String name){
            Map<String, Object> map=new HashMap<>();
            map.put("hotelCode",num);
            map.put("hotelName",name);
            retrofitService.getUnlicensedNum(map).enqueue(callback);
        }
        //上传xx信息,使用@Body 注解
        public void postMultipartBody(Callback<ResponseBody> callback, String key,File file, String name){
            MultipartBody.Builder builder=  new MultipartBody.Builder().setType(MultipartBody.FORM);
            if(file.exists()) {
                builder.addFormDataPart("access_token", key);
                builder.addFormDataPart("name", name);
                builder.addFormDataPart("image", ImageUtil.imageToBase64(file.getPath()));
                builder.addFormDataPart("image_type", "BASE64");
            }
            retrofitService.getUnlicensedCheck(builder.build()).enqueue(callback);
        }
        //上传xx信息,带文件,使用@Body 注解
        public void postMultipartBody2(Callback<ResponseBody> callback, HotelInfo hotelInfo,String pictureCardPath,String picturePath){
            Gson gson=new Gson();
            String json= gson.toJson(hotelInfo);
            File file = new File(pictureCardPath);
            File file2 = new File(picturePath);
            MultipartBody.Builder builder=  new MultipartBody.Builder().setType(MultipartBody.FORM);
            if(!file.exists()&&!file2.exists()) {
                try {
                    builder.addFormDataPart("info", json);
                    builder.addFormDataPart("file",file.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file));
                    builder.addFormDataPart("file2",file2.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file2));
                    retrofitService.getHotelInfoFile(builder.build()).enqueue(callback);
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.i("WebManager","上传异常");
                }
            }
        }
        
    }

    retrofit服务类

    public interface RetrofitService {
        @FormUrlEncoded
        @POST("/Hotels/ExpressServlet")
        Call<ResponseBody> getWarrant(@Field("type") String type, @Field("E_Code") String code, 
        @Field("applicationFormId") String id);
    
        @FormUrlEncoded
        @POST("Hotels/NoRegisterServlet")
        Call<ResponseBody> getUnlicensedNum(@FieldMap Map<String,Object> fieldMap);
    
        @POST("/rest/2.0/face/v3/person/verify")
        Call<ResponseBody> getUnlicensedCheck(@Body MultipartBody builder);
    
        @Headers("Connection: close" )
        @POST("/Hotels/UploadFileImgServlet")
        Call<ResponseBody> getHotelInfoFile(@Body MultipartBody builder);
    
    }

    RxJava相关阅读

    Android异步框架 RxJava

    Retrofit代码混淆配置

    -dontwarn retrofit.**
    -keep class retrofit.** { *; }
    -keepattributes Signature
    -keepattributes Exceptions
  • 相关阅读:
    引用与指针的区别联系
    单链表热点面试题
    C语言实现的单链表
    C语言实现的顺序表
    自己实现的库函数2(memset,memcmp,memcpy,memmove)
    自己实现的库函数1(strlen,strcpy,strcmp,strcat)
    Python文件练习_注册
    Python文件练习_自动生成密码文件
    Python文件练习_读取文件并计算平均分
    Python学习笔记七_文件读写
  • 原文地址:https://www.cnblogs.com/94xiyang/p/9629205.html
Copyright © 2011-2022 走看看