Retrofit网络请求,工具类的封装(二)

878 阅读3分钟

对于Retrofit的使用我就不介绍了,使用也不难,随便去搜两篇文章看看。 我主要介绍的就是如何封装,简便使用。

一、Retrofit工具类的封装(核心类)
	 /**
	 * Retrofit工具类
	 */
	public class RetrofitUtils {
		public static final String BASE_URL = "http://XXX";
		/**
		 * 超时时间
		 */
		public static final int TIMEOUT = 60;
		private static volatile RetrofitUtils mInstance;
		private Retrofit mRetrofit;

		public static RetrofitUtils getInstance() {
			if (mInstance == null) {
				synchronized (RetrofitUtils.class) {
					if (mInstance == null) {
						mInstance = new RetrofitUtils();
					}
				}
			}
			return mInstance;
		}

		private RetrofitUtils() {
			initRetrofit();
		}

		/**
		 * 初始化Retrofit
		 */
		private void initRetrofit() {
			OkHttpClient.Builder builder = new OkHttpClient.Builder();
			// 设置超时
			builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
			builder.readTimeout(TIMEOUT, TimeUnit.SECONDS);
			builder.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
			OkHttpClient client = builder.build();
			mRetrofit = new Retrofit.Builder()
					// 设置请求的域名
					.baseUrl(BASE_URL)
					// 设置解析转换工厂,用自己定义的
					.addConverterFactory(ResponseConvert.create())
					.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
					.client(client)
					.build();
		}

		/**
		 * 创建API
		 */
		public <T> T create(Class<T> clazz) {
			return mRetrofit.create(clazz);
		}
	}

代码很简单,创建后台请求接口,调用create即可。

二、Converter.Factory的封装
自己采用Gson封装解析。
/**
 * 自定义Gson解析转换
 */

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

	/**
	 * 转换的方法
	 */
	@Override
	public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
		return new BodyConverter<>(type);
	}

	private class BodyConverter<T> implements Converter<ResponseBody, T> {
		private Gson gson;
		private Type type;

		public BodyConverter(Type type) {
			this.type = type;
			gson = new GsonBuilder()
					.registerTypeHierarchyAdapter(List.class, new ListTypeAdapter())
					.create();
		}

		@Override
		public T convert(ResponseBody value) throws IOException {
			String json = value.string();
			return gson.fromJson(json, type);
		}
	}

	/**
	 * 空列表的转换
	 */
	private static class ListTypeAdapter implements JsonDeserializer<List<?>> {
		@Override
		public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
			if (json != null && json.isJsonArray()) {
				JsonArray array = json.getAsJsonArray();
				Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
				java.util.List list = new ArrayList<>();
				for (int i = 0; i < array.size(); i++) {
					JsonElement element = array.get(i);
					Object item = context.deserialize(element, itemType);
					list.add(item);
				}
				return list;
			} else {
				//和接口类型不符,返回空List
				return Collections.EMPTY_LIST;
			}
		}
	}
}
三、Retrofit网络请求基类的封装
/**
 * 后台统一接口API
 */

public interface ServerApi {
	// 联系人编辑
	@POST(URLS.LOGIN)
	Observable<ResponseBean<LoginBean>> login(@Body RequestBody requestBody);
}

/**
 * 请求网络业务的基类,AppPresenterr 的封装
 */

public class AppPresenter {
	protected ServerApi mApi = RetrofitUtils.getInstance().create(ServerApi.class);
	private static final Gson gson = new Gson();

	/**
	 * 1. 转换
	 * 统一处理一些动作
	 */
	public static <T> void convert(Observable<ResponseBean<T>> observable, Observer<T> observer) {
		observable
				.map(new Function<ResponseBean<T>, T>() {
					@Override
					public T apply(ResponseBean<T> httpResult) throws Exception {
						// 打印响应的对象
						LogUtils.object(httpResult);
						// TODO 实际开发的时候统一处理一些东西
						if (httpResult == null || httpResult.head == null) {
							throw new RuntimeException("请求数据异常");
						} else if (!"1".equals(httpResult.head.bcode)) {
							throw new RuntimeException(httpResult.head.bmessage);
						}
						return httpResult.data;
					}
				})
				.subscribeOn(Schedulers.io())
				.observeOn(AndroidSchedulers.mainThread())
				.subscribe(observer);
	}

	/**
	 *  2. 执行的方法
	 */
	public static <T> void execute(Observable<ResponseBean<T>> observable, Observer<ResponseBean<T>> observer) {
		observable.subscribeOn(Schedulers.io())
				.observeOn(AndroidSchedulers.mainThread())
				.subscribe(observer);
	}

	/**
	 * 3.请求数据是Json,Json转成RequestBody
	 */
	public static RequestBody createRequestBody(Object obj) {
		RequestBean bean = new RequestBean<>(obj);
		String json = gson.toJson(bean);
		// 打印请求的Json
		LogUtils.json(json);
		RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
		return body;
	}

}
有三个通用的方法:
  1.convert方法,转换、统一处理网络请求,将公共处理部分放在这方法里面。
  2.execute方法,只执行,不做任何处理操作,适用于一些不能统一处理的接口。
  3.createRequestBody方法,就是统一创建请求的RequestBody。
四、具体网络请求业务类
/**
 * 登录的业务类
 */

public class LoginPresenter extends AppPresenter {
	/**
	 * 登录的接口
	 */
	public void login(LoginData data, Observer<LoginBean> observer) {
		Observable<ResponseBean<LoginBean>> login = mApi.login(createRequestBody(data));
		// 转换
		convert(login, observer);
	}
}
五、测试和使用
/**
 * 调用登录接口
 */
public void open(View view) {
	LoginData loginData = new LoginData("135****5219", "12***56");
	presenter.login(loginData, new DialogObserver<LoginBean>(getAppActivity()) {
		@Override
		public void onNext(LoginBean data) {
			// TODO 做登录的成功的操作
			Toast.makeText(getAppActivity(), "" + data.userInfo.nickName, Toast.LENGTH_SHORT).show();
		}
	});
}
六、补充,对于Observer需要再次封装。
1.如调用登录要显示Dialog
2.如Activity销毁要取消请求。
3.结合加载数据各种状态页面,如:加载中、加载失败、网络异常、数据为空等等
  这些都是可以统一封装在Observer<T>里面。