Android--Retrofit浅入深出

官网:http://square.github.io/retrofit/

官方定义:
A type-safe HTTP client for Android and Java

一:配置
app:build.gradle:

compile 'com.squareup.retrofit2:retrofit:2.0.2'

二:例子

–1:BaseResponse

public class BaseResponse {
    String returnCode;
    String msg;
    String result;
    boolean success;


    public String getReturnCode() {
        return returnCode;
    }

    public void setReturnCode(String returnCode) {
        this.returnCode = returnCode;
    }

    public String getMsg() {
        return msg;
    }

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

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }
}

–2:HtppService


public interface HttpService {
    @FormUrlEncoded
    @POST("/frist/noIntercept/user/login.do")
    Call<UserResponse> getUserByLogin(@Field("password") String password, @Field("phone") String phone);

}

–3:User

public class User {
    private int id;
    private boolean invalid;
    private int status;
    private long createdDatetime;
    private long updatedDatetime;
    private int orderTag;
    private String name;
    private String phone;
    private String password;
    private String slogan;
    private String imagpath;
    private int userid;
    private int sex;


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public boolean isInvalid() {
        return invalid;
    }

    public void setInvalid(boolean invalid) {
        this.invalid = invalid;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public long getCreatedDatetime() {
        return createdDatetime;
    }

    public void setCreatedDatetime(long createdDatetime) {
        this.createdDatetime = createdDatetime;
    }

    public long getUpdatedDatetime() {
        return updatedDatetime;
    }

    public void setUpdatedDatetime(long updatedDatetime) {
        this.updatedDatetime = updatedDatetime;
    }

    public int getOrderTag() {
        return orderTag;
    }

    public void setOrderTag(int orderTag) {
        this.orderTag = orderTag;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSlogan() {
        return slogan;
    }

    public void setSlogan(String slogan) {
        this.slogan = slogan;
    }

    public String getImagpath() {
        return imagpath;
    }

    public void setImagpath(String imagpath) {
        this.imagpath = imagpath;
    }

    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }
}

–4:BaseResponse

public class UserResponse extends BaseResponse {

    private RespData data;

    public RespData getData() {
        return data;
    }

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

    public static class RespData {
        private User user;

        public User getUser() {
            return user;
        }

        public void setUser(User user) {
            this.user = user;
        }


    }
}

–5:MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener { 
private static final String WEB_URL = "http://192.168.1.115:8080";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.start).setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.start:
                getUser();
                break;
        }
    }


    private void getUser() {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).addConverterFactory(GsonConverterFactory.create()).build();

        HttpService httpService = retrofit.create(HttpService.class);
        String phone = "15029206553";
        String password = "123456";
        Call<UserResponse> call = httpService.getUserByLogin(password, phone);
        call.enqueue(new Callback<UserResponse>() {
            @Override
            public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
                Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(Call<UserResponse> call, Throwable t) {
           }
        });
    }
}

注:可以看出,接口返回的是需要的JAVA对象,不是而不是byte[]或String!Retrofit内部默认使用Gson解析相关数据。

三:相关方法:

—-1:支持:GET, POST, PUT, DELETE, and HEAD!

@GET("users/list")
@GET("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Query("password") String password, @Query("phone") String phone);

也可以直接在请求接口中显示需要的参数,类似于:

@GET("users/list?sort=desc")
@GET("/frist/noIntercept/user/login.do?password=123456&phone=15029206553")
Call<UserResponse> getUserByLogin();

使用技巧:当我们使用POST方式无参去请求数据的时候,请修改为无参的GET请求。
- - 2:可以动态更新请求块里面的参数和方法,一个相应的参数必须和@Path保持同样的字符串

 @GET("group/{id}/users")
     Call<List<User>> groupList(@Path("id") int groupId);
@GET("/frist/noIntercept/{user}/login.do?password=123456&phone=15029206553")
Call<UserResponse> getUserByLogin(@Path("user") String user);

也可以使用查询方法来添加相关参数,类似于:

 @GET("group/{id}/users")
      Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
@GET("/frist/noIntercept/{user}/login.do")
Call<UserResponse> getUserByLogin(@Path("user") String user,@Query("password") String password, @Query("phone") String phone);

—-3:Map使用

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

使用技巧:对于复杂参数,可以使用Map来组合请求对象。

—-4:JavaBean作为请求体<添加转换器,若没有添加,只能使用response>

@POST("users/new")Call<User> createUser(@Body User user);
public class LoginBean {
    String password;
    String phone;

    public  LoginBean(String password, String phone){
        this.password=password;
        this.phone=phone;
    }
}

@POST("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Body LoginBean loginBean);
String phone = "15029206553";
String password = "123456";
LoginBean loginBean=new LoginBean(password,phone);
Call<UserResponse> call = httpService.getUserByLogin(loginBean);

注意点:使用此种方式传参,需要修改后台正常获取参数的方式,慎用。

—-5:指定请求编码类型

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
@FormUrlEncoded
@POST("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Field("password") String password, @Field("phone") String phone);

—-6:操作Head

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

也可以写成下面:

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

注:当@Headers{}为空时,则会自动忽略。

—-7:每个请求都添加Head:<动态更新>

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

—-8:使用ConverterFactory来修改默认返回数据解析<可自定义转换器>
Retrofit默认使用GSON进行相关数据解析。

这里写图片描述

下面是一个使用GsonConverterFactory生成JSON解析数据的例子:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();
GitHubService service = retrofit.create(GitHubService.class);

四:简单封装:
–1:RetrofitUtil:

public class RetrofitUtil {
    private static final String WEB_URL = "http://192.168.1.115:8080";

    public static HttpService instanceHttpService() {
     Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).addConverterFactory(GsonConverterFactory.create()).build();
     HttpService httpService = retrofit.create(HttpService.class);
        return httpService;
    }
}

–2:MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.start).setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.start:
                getUser();
                break;
        }
    }


    private void getUser() {
        String phone = "15029206553";
        String password = "123456";
        Call<UserResponse> call = RetrofitUtil.instanceHttpService().getUserByLogin(password, phone);
        call.enqueue(new Callback<UserResponse>() {
            @Override
            public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
                Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(Call<UserResponse> call, Throwable t) {

            }
        });
    }
}

可以看出来:代码量减少很多。

五:深度封装:
拦截器是一个强大的机制,可以监视,重写,然后重新调用。
–1:
调用链的调用(请求)是每个拦截的执行的一个关键部分:

public class LoggingInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        long t1 = System.nanoTime();
        .....
       // request.url(), chain.connection(), request.headers();

        Response response = chain.proceed(request);
        long t2 = System.nanoTime();
        ....
       // response.request().url(), (t2 - t1) / 1e6d, response.headers();

        return response;
    }
}

这里写图片描述

–2:Application interceptors:
—-:拦截器分为应用拦截和网络:
打印拦截器:

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder()
        .addInterceptor(logging)//添加打印拦截器
        .connectTimeout(30, TimeUnit.SECONDS)//设置请求超时时间
        .retryOnConnectionFailure(true)//设置出现错误进行重新连接。
        .build();
注意:多了一个.client()方法:
Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).client(httpClient).addConverterFactory(GsonConverterFactory.create()).build();

因为OKHTTP支持重定向,而Retrofit是基于OKHTTP3建立各种模块的。

–3:重定向

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new LoggingInterceptor())
    .build();

Request request = new Request.Builder()
    .url("http://www.publicobject.com/helloworld.txt")
    .header("User-Agent", "OkHttp Example")
    .build();

Response response = client.newCall(request).execute();
response.body().close();

结果为:

INFO: Sending request http://www.publicobject.com/helloworld.txt on null
User-Agent: OkHttp Example

INFO: Received response for https://publicobject.com/helloworld.txt in 1179.7ms
Server: nginx/1.4.6 (Ubuntu)
Content-Type: text/plain
Content-Length: 1759
Connection: keep-alive

–4:网络监听器

.addNetworkInterceptor(new LoggingInterceptor())

应用和网络拦截器比对:

应用拦截器:
--1:不用担心请求时重定向和定向次数
--2:调用次数为一次<缓存>
--3:允许重试,多次调用请求链<okhttp请求是通过链路进行管理的>
--4:可以观察应用的意图,在请求或者返回数据的时候进行相关匹配以及处理
网络拦截器:
--1:观察数据传输

六:特殊需求:
–1:所有网络请求都添加token:

Interceptor mToken = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        if (You.token == null || alreadyHasAuthorizationHeader(originalRequest)) {
            return chain.proceed(originalRequest);
        }
        Request authorised = originalRequest.newBuilder()
                .header("Authorization", You.token)
                .build();
        return chain.proceed(authorised);
    }
};

public static boolean alreadyHasAuthorizationHeader(Request request) {
    if (request != null) {
        if (request.headers() != null) {
            return true;
        } else {
            return false;
        }
    }
    return false;
}

–1:
—-:if判断,当你有token的时候才会进行添加,或者请求验证中已经有hrader了,那么就不执行这个token了。
—-:header 的 key 通常是 Authorization,可以修改

2–:添加公私密钥

MarvelSigningInterceptor signingInterceptor = new MarvelSigningInterceptor(KeyValue.MARVEL_PUBLIC_KEY, KeyValue.MARVEL_PRIVATE_KEY);

3–:添加缓存策略

File cacheFile = new File(context.getCacheDir(), "ZhiBookCache");
  Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
  Interceptor interceptorCache = new Interceptor() {
      @Override
      public Response intercept(Chain chain) throws IOException {
          Request request = chain.request();
          if (!NetworkStateUtils.getInstance(context).isConnection()) {
              request = request.newBuilder()
                      .cacheControl(CacheControl.FORCE_CACHE)
                      .build();
          }
          Response response = chain.proceed(request);
          if (NetworkStateUtils.getInstance(context).isConnection()) {
              int maxAge = 0 * 60;
              // 有网络时 设置缓存超时时间0个小时
              response.newBuilder()
                      .header("Cache-Control", "public, max-age=" + maxAge)
                      .removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
                      .build();
          } else {
              // 无网络时,设置超时为4周
              int maxStale = 60 * 60 * 24 * 28;
              response.newBuilder()
                      .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                      .removeHeader("Pragma")
                      .build();
          }
          return response;
      }
  };

七:再次封装:
–1:

public abstract class RCllBack<T> implements Callback<T> {
    @Override
    public void onResponse(Call<T> call, Response<T> response) {
        onSuccess(response.body());
    }

    @Override
    public void onFailure(Call<T> call, Throwable t) {

    }


    public abstract void onSuccess(T response);
}

–2:

public abstract class RCllBaackComm<T> implements Callback<T> {
    @Override
    public void onResponse(Call<T> call, Response<T> response) {

        BaseResponse resp = (BaseResponse) response.body();
        //在此可以根据自己的功能需求进行相关判断
    }

    @Override
    public void onFailure(Call<T> call, Throwable t) {
        onFailed(new CommError("网络错误"));
    }

    public abstract void onSuccess(T response);

    public abstract void onFailed(CommError error);


}

概念理解:

onResponse: HTTP有效也就是请求返回为200,返回数据
因此在此方法里面,可以根据自己和服务器返回值的约定进行相关处理;

onFailure:当请求地址不存在或者其他原因<无网络>

以下为三种不同方法用起来的差异:

Call<UserResponse> call = RetrofitUtil.service.getUserByLogin(password, phone);
//1
call.enqueue(new Callback<UserResponse>() {
    @Override
    public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
        Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();
    }

    @Override
    public void onFailure(Call<UserResponse> call, Throwable t) {

    }
});
//2
call.enqueue(new RCllBack<UserResponse>() {
    @Override
    public void onSuccess(UserResponse response) {

    }
});
//3
call.enqueue(new RCllBaackComm<UserResponse>() {
    @Override
    public void onSuccess(UserResponse response) {

    }

    @Override
    public void onFailed(CommError error) {

    }
});

相关依赖引入:

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
compile 'com.squareup.okhttp3:okhttp:3.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'

本次源码获取地址:
github:https://github.com/erhutime/NetWorking

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值