RetrofitRetrofit 2.0android开发杂识

Retrofit2.0项目中实践

2016-04-25  本文已影响6000人  ed407c8602e0

前言

项目中开始使用retrofit2.0作为网络框架,注解的形式使用起来确实简洁。2.0版本相比之前有了比较大的变化,所以屡次在群里看到有童鞋问怎样实现上传下载?肿么获取原始的json?本文主要来回答这些问题。


官网

github项目地址

https://github.com/square/retrofit

官方文档

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

基本的使用姿势(基本配置,get,post请求等,就不重复造轮子了)

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0915/3460.html


实践

建议起码看完retrofit2.0的基本用法再来看本文。

1. 返回原始的的json

场景是这样,服务端返回一个不定类型的json数据,无法确定映射的Gson对象。或者本猿就是要看原汁原味的json肿么办?我依旧使用GsonConverterFactory作为转换器,返回的对象定义为String。。结果不行。。。各种研究+求教后得到解决方案。应该使用ScalarsConverterFactory,关键代码如下

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

api

    @GET("user/login")
    Call<String> upgrade(@Query("account") String account,
                    @Query("password") String password,
                    @Query("callback") String callback);

现在的问题肯定是ScalarsConverterFactory哪来的?其实官方的项目中就有,地址点我

打开红色箭头指向的文件夹,将retrofit-master\retrofit-converters\scalars\src\main\java\retrofit2\converter\scalars这个目录下的三个文件放到自己的工程下就可以使用了。



回调的string就是原始的json字符串,当然不是json的字符串也可以。为了方便大家,这3个文件直接贴在下面的“下载”模块了,直接copy。

2. 上传

上传的场景是一个表单中既有文本信息又有图片上传,当然单一的就更简单了,去掉相关的参数就行了。

    @Multipart
    @POST("user/register")
    Call<ResponseJson> register(@Part("key1") RequestBody param1,
                                           @Part("key2") RequestBody param2,
                                           @Part("key3\"; filename=\"fileName.png") RequestBody param3
    );

key的对应post请求中的key,根据接口文档中的定义自行切换。第三个参数对应的是要上传的图片,注意@Part("key3"; filename="fileName.png") 中key3是对应post中的key,而fileName.png需要替换成自己的文件名称。接着构建参数。

        RequestBody param1= RequestBody.create(MediaType.parse("text/plain"),  account);
        RequestBody param2= RequestBody.create(MediaType.parse("text/plain"),  password);
        RequestBody imageParam3= RequestBody.create(MediaType.parse("image/*"),  file);

account, password是页面传入的参数,注意第三个参数也就是图片上传的参数,传入一个File对象,可以是SD卡中的图片。将这些参数扔进前面的register方法,请求就发成功了。这里只写了实现的核心点,如果需要详细实现示例,请留言。

3. 下载

从服务器下载一个文件,可能你还需要显示进度条。别急,本猿这些统统有。retrofit老惯例,先定义api。

    /**
     * 下载文件
     */
    @GET("{fileName}")
    Call<ResponseBody> getFile(@Path("fileName")String fileName);

注意这里的返回的是ResponseBody对象,这是okhttp中的对象。

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();
        APIService apiService = retrofit.create(APIService.class);
        Call<ResponseBody> call = apiService.getFile(fileName);
        call.enqueue(callback);

这里的baseUrl就是是下载的地址,但是baseUrl是以'/'结尾的url,如果你的下载地址是一个完整的url的话,你需要截取字符串,把后面一段url作为fileName参数拼接上去。如“http://download/1.png”,截取成“http://download/” + “1.png”,前一段是baseUrl,后面是fileName。这里的ScalarsConverterFactory要处理下,才能返回ResponseBody对象。

public final class ScalarsConverterFactory extends Converter.Factory {
    public static ScalarsConverterFactory create() {
        return new ScalarsConverterFactory();
    }

    private ScalarsConverterFactory() {
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        if (type == String.class
                || type == boolean.class
                || type == Boolean.class
                || type == byte.class
                || type == Byte.class
                || type == char.class
                || type == Character.class
                || type == double.class
                || type == Double.class
                || type == float.class
                || type == Float.class
                || type == int.class
                || type == Integer.class
                || type == long.class
                || type == Long.class
                || type == short.class
                || type == Short.class
                || type == ResponseBody.class
                ) {
            return ScalarRequestBodyConverter.INSTANCE;
        }
        return null;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        if (type == String.class) {
            return StringResponseBodyConverter.INSTANCE;
        }
        if (type == Boolean.class || type == boolean.class) {
            return BooleanResponseBodyConverter.INSTANCE;
        }
        if (type == Byte.class || type == byte.class) {
            return ByteResponseBodyConverter.INSTANCE;
        }
        if (type == Character.class || type == char.class) {
            return CharacterResponseBodyConverter.INSTANCE;
        }
        if (type == Double.class || type == double.class) {
            return DoubleResponseBodyConverter.INSTANCE;
        }
        if (type == Float.class || type == float.class) {
            return FloatResponseBodyConverter.INSTANCE;
        }
        if (type == Integer.class || type == int.class) {
            return IntegerResponseBodyConverter.INSTANCE;
        }
        if (type == Long.class || type == long.class) {
            return LongResponseBodyConverter.INSTANCE;
        }
        if (type == Short.class || type == short.class) {
            return ShortResponseBodyConverter.INSTANCE;
        }
        if(type == ResponseBody.class){
            return ScalarResponseBodyConverter.INSTANCE;
        }
        return null;
    }
}
final class ScalarResponseBodyConverters {
  private ScalarResponseBodyConverters() {
  }

  static final class StringResponseBodyConverter implements Converter<ResponseBody, String> {
    static final StringResponseBodyConverter INSTANCE = new StringResponseBodyConverter();

    @Override public String convert(ResponseBody value) throws IOException {
      String valueStr = value.string();
      return valueStr;
    }
  }

  static final class BooleanResponseBodyConverter implements Converter<ResponseBody, Boolean> {
    static final BooleanResponseBodyConverter INSTANCE = new BooleanResponseBodyConverter();

    @Override public Boolean convert(ResponseBody value) throws IOException {
      return Boolean.valueOf(value.string());
    }
  }

  static final class ByteResponseBodyConverter implements Converter<ResponseBody, Byte> {
    static final ByteResponseBodyConverter INSTANCE = new ByteResponseBodyConverter();

    @Override public Byte convert(ResponseBody value) throws IOException {
      return Byte.valueOf(value.string());
    }
  }

  static final class CharacterResponseBodyConverter implements Converter<ResponseBody, Character> {
    static final CharacterResponseBodyConverter INSTANCE = new CharacterResponseBodyConverter();

    @Override public Character convert(ResponseBody value) throws IOException {
      String body = value.string();
      if (body.length() != 1) {
        throw new IOException(
            "Expected body of length 1 for Character conversion but was " + body.length());
      }
      return body.charAt(0);
    }
  }

  static final class DoubleResponseBodyConverter implements Converter<ResponseBody, Double> {
    static final DoubleResponseBodyConverter INSTANCE = new DoubleResponseBodyConverter();

    @Override public Double convert(ResponseBody value) throws IOException {
      return Double.valueOf(value.string());
    }
  }

  static final class FloatResponseBodyConverter implements Converter<ResponseBody, Float> {
    static final FloatResponseBodyConverter INSTANCE = new FloatResponseBodyConverter();

    @Override public Float convert(ResponseBody value) throws IOException {
      return Float.valueOf(value.string());
    }
  }

  static final class IntegerResponseBodyConverter implements Converter<ResponseBody, Integer> {
    static final IntegerResponseBodyConverter INSTANCE = new IntegerResponseBodyConverter();

    @Override public Integer convert(ResponseBody value) throws IOException {
      return Integer.valueOf(value.string());
    }
  }

  static final class LongResponseBodyConverter implements Converter<ResponseBody, Long> {
    static final LongResponseBodyConverter INSTANCE = new LongResponseBodyConverter();

    @Override public Long convert(ResponseBody value) throws IOException {
      return Long.valueOf(value.string());
    }
  }

  static final class ShortResponseBodyConverter implements Converter<ResponseBody, Short> {
    static final ShortResponseBodyConverter INSTANCE = new ShortResponseBodyConverter();

    @Override public Short convert(ResponseBody value) throws IOException {
      return Short.valueOf(value.string());
    }
  }

  static final class ScalarResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
    static final ScalarResponseBodyConverter INSTANCE = new ScalarResponseBodyConverter();

    @Override public ResponseBody convert(ResponseBody value) throws IOException {
      return value;
    }
  }
}
final class ScalarRequestBodyConverter<T> implements Converter<T, RequestBody> {
  static final ScalarRequestBodyConverter<Object> INSTANCE = new ScalarRequestBodyConverter<>();
  private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain; charset=UTF-8");

  private ScalarRequestBodyConverter() {
  }

  @Override public RequestBody convert(T value) throws IOException {
    return RequestBody.create(MEDIA_TYPE, String.valueOf(value));
  }
}

这3个类请直接贴到自己的工程里。在callback里我们可以拿到原始的ResponseBody。

  @Override
  public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
      ResponseBody responseBody = response.body();
      InputStream inputStream = responseBody.byteStream();
      if (inputStream != null) {
          totalSize = (int) responseBody.contentLength();
          saveFileTask(inputStream);
      }
  }

有了文件流和文件大小,相信机智的大家可以搞定下载和进度条了吧。

后话

还有些retrofit2.0的使用,比如搞定cookie,拦截器什么的如果大家需要请留言,其他需求也可以留言讨论。如果觉得有用请帮忙戳喜欢。。。

关注我(微信扫一扫)

上一篇下一篇

猜你喜欢

热点阅读