目录
2、Restful请求的处理--同接口,使用不同方法,可以产生不同的作用
4、文件下载功能的实现--AsyncTask、线程池并发的实现
使用retrofit进行网络请求封装
1、网络请求接口创建--retrofit的使用
1.1 使用注解描述网络请求
位于latte-core模块下的RestService,接口,内部含有网络请求的get、post、download等方法。
主要作用:通过动态代理方式,将注解生成网络请求的request。
@GET
Call<String> get(@Url String url, @QueryMap Map<String, Object> params);
@FormUrlEncoded
@POST
Call<String> post(@Url String url, @FieldMap Map<String, Object> params);
@POST
Call<String> postRaw(@Url String url, @Body RequestBody body);
1.2 网络请求接口的实例创建
位于latte-core模块下的RestCreator,内部含有OKHttp和Retrofit的创建。
主要作用:创建RestService的实例,单例,确保全局唯一性。
/**
* 构建全局Retrofit客户端
*/
private static final class RetrofitHolder{
private static final String BASE_URL = Latte.getConfiguration(ConfigKeys.API_HOST) ;
private static final Retrofit RETROFIT_CLIENT = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(OKHttpHolder.OK_HTTP_CLIENT)
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
private static final class OKHttpHolder{//对okhttpclient处理,okhttp惰性初始化
private static final int TIME_OUT = 60;
private static final OkHttpClient.Builder BUILDER = new OkHttpClient.Builder();
private static final ArrayList<Interceptor> INTERCEPTORS = Latte.getConfiguration(ConfigKeys.INTERCEPTOR);
private static OkHttpClient.Builder addInterceptor(){
if (INTERCEPTORS != null && !INTERCEPTORS.isEmpty()){
for (Interceptor interceptor: INTERCEPTORS) {
BUILDER.addInterceptor(interceptor);
}
}
return BUILDER;
}
private static final OkHttpClient OK_HTTP_CLIENT = addInterceptor()
.connectTimeout(TIME_OUT, TimeUnit.SECONDS)
.build();
}
/**
* Service接口
*/
private static final class RestServiceHolder{
private static final RestService REST_SERVICE = RetrofitHolder.RETROFIT_CLIENT.create(RestService.class);
}
public static RestService getRestService(){
return RestServiceHolder.REST_SERVICE;
}
2、Restful请求的处理--同接口,使用不同方法,可以产生不同的作用
使用建造者模式进行传参,链式调用,将使用和构建相分离,确保初始化唯一。
位于latte-core模块下的RestClient,内部含有call方法的请求,根据调用的方法不同,发起不同的call请求。
主要作用:创建RestService的实例,单例,确保全局唯一性。
private void request(HttpMethod method){
final RestService service = RestCreator.getRestService();
Call<String> call = null;
switch (method){
case GET:
call = service.get(URL,PARAMS);
break;
case POST:
call = service.post(URL,PARAMS);
break;
case POST_RAW:
call = service.postRaw(URL, BODY);
break;
case PUT:
call = service.put(URL,PARAMS);
break;
case PUT_RAW:
call = service.putRaw(URL, BODY);
break;
case DELETE:
call = service.delete(URL,PARAMS);
break;
case UPLOAD:
final RequestBody requestBody =
RequestBody.create(MediaType.parse(MultipartBody.FORM.toString()),FILE);//根据文件和MediaType.parse(MultipartBody.FORM.toString()):相当于请求头---形成请求体
final MultipartBody.Part body =
MultipartBody.Part.createFormData("file",FILE.getName(),requestBody);//请求体以多部分方式上传
call = RestCreator.getRestService().upload(URL,body);
break;
default:
break;
}
if (call != null){
call.enqueue(getRequestCallback());
}
}
位于latte-core模块下的RestClientBuilder,内部含有方法接受网络请求需要的参数。
主要作用:将传入的参数通过build()方法传回RestClient类中,为后续call请求做准备。
public final RestClientBuilder loader(Context context, LoaderStyle style){
this.mContext = context;
this.mLoaderStyle = style;
return this;
}
public final RestClientBuilder loader(Context context){//使用默认style
this.mContext = context;
this.mLoaderStyle = LoaderStyle.BallClipRotatePulseIndicator;
return this;
}
public final RestClient build(){
return new RestClient(mUrl,PARAMS,mIRequest,mDownloadDir,mExtension,mName,mISuccess,mIFailure,mIError,mBody,mFile,mContext,mLoaderStyle);
}
位于latte-core模块下的RequestCallbacks,继承自Callback,内部含有call方法请求后的回调。
主要作用:根据call方法的请求请求结果回调不同的接口:ISuccess、IError等接口,实现不同的结果处理
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()){
if(call.isExecuted()){
if(SUCCESS != null){
SUCCESS.onSuccess(response.body());
}
}
}else {
if(ERROR != null){
ERROR.onError(response.code(), response.message());
}
}
stopLoading();
}
@Override
public void onFailure(Call<String> call, Throwable t) {
if(FAILURE != null){
FAILURE.onFailure();
}
if(REQUEST != null){
REQUEST.onRequestEnd();
}
stopLoading();
}
位于latte-core模块下的ISuccess、IError等接口,内部含有call方法请求后的结果方法。
主要作用:使用在call后结果处理,根据结果选择回调不同方法。----具体的实现在链式调用中体现。
public interface ISuccess {
void onSuccess(String response);
}
public interface IError {
void onError(int code, String msg);
}
3、Loading框架集成和完善--在dialog中显示
考虑网络较差情况下的网络加载,这时候会在UI上出现一个Loader;
在retrofit的回调中进行loader的删除。
3.1 LoaderView的创建
位于latte-core模块下的LoaderCreator,内部通过反射获取View,官方每次请求都反射一次,这里使用WeakHashmap进行缓存。
主要作用:创建出Loader的View。
private static final WeakHashMap<String, Indicator> LOADING_MAP = new WeakHashMap<>();
static AVLoadingIndicatorView create(String type, Context context){
final AVLoadingIndicatorView avLoadingIndicatorView = new AVLoadingIndicatorView(context);
if (LOADING_MAP.get(type) == null){
final Indicator indicator = getIndicator(type);
LOADING_MAP.put(type, indicator);
}
avLoadingIndicatorView.setIndicator(LOADING_MAP.get(type));
return avLoadingIndicatorView;
}
private static Indicator getIndicator(String name){
if(name == null || name.isEmpty()){
return null;
}
final StringBuilder drawableClassName = new StringBuilder();
if(!name.contains(".")){
final String defaultPackageName = AVLoadingIndicatorView.class.getPackage().getName();//反射获取包名
drawableClassName.append(defaultPackageName)
.append(".indicators")
.append(".");
}
drawableClassName.append(name);//生成具体View
try {
final Class<?> drawableClass = Class.forName(drawableClassName.toString());
return (Indicator) drawableClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
3.2 LoaderView的显示
位于latte-core模块下的LatteLoader,内部与dialog绑定。
主要作用:显示View。
public static void showLoading(Context context, String type){
final AppCompatDialog dialog = new AppCompatDialog(context, R.style.dialog);
final AVLoadingIndicatorView avLoadingIndicatorView = LoaderCreator.create(type,context);
dialog.setContentView(avLoadingIndicatorView);//作为根视图加入
int deviceWidth = DimenUtil.getScreenWidth();
int deviceHeight = DimenUtil.getScreenHeight();
final Window dialogWindow = dialog.getWindow();
if(dialogWindow != null){
final WindowManager.LayoutParams lp = dialogWindow.getAttributes();//获取对话框当前的参数值
lp.width = deviceWidth/LOADER_SIZE_SCALE;
lp.height = deviceHeight/LOADER_SIZE_SCALE;
lp.height = lp.height+deviceHeight/LOADER_OFFSET_SCALE;
lp.gravity = Gravity.CENTER;
}
LOADERS.add(dialog);
dialog.show();
}
4、文件下载功能的实现--AsyncTask、线程池并发的实现
使用AsyncTask进行异步下载
位于latte-core模块下的DownloadHandler,内部进行了异步下载处理。
主要作用:调用download请求方法。
public final void handleDownload(){
if (REQUEST != null){
REQUEST.onRequestStart();//请求开始的回调
}
RestCreator.getRestService().download(URL,PARAMS)
.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()){
final ResponseBody responseBody = response.body();
final SaveFileTask task = new SaveFileTask(REQUEST, SUCCESS);
//使用线程池方法进行下载,内部默认的线程池:核心1,最大20,时间3分
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,DOWNLOAD_DIR,EXTENSION,responseBody,NAME);
//这里一定要注意判断,否则文件下载不全
if (task.isCancelled()){//下载结束
if (REQUEST != null){
REQUEST.onRequestEnd();
}
}
}else {
if (ERROR != null){
ERROR.onError(response.code(), response.message());
}
}
RestCreator.getParams().clear();
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
if (FAILURE != null){
FAILURE.onFailure();
RestCreator.getParams().clear();
}
}
});
}
位于latte-core模块下的SaveFileTask,继承自AsyncTask。
主要作用:进行下载的处理,写入文件(使用IO流)。
@Override
protected File doInBackground(Object... objects) {
String downloadDir = (String) objects[0];
String extension = (String) objects[1];
final ResponseBody body = (ResponseBody) objects[2];
final String name = (String) objects[3];
final InputStream is = body.byteStream();
if (downloadDir == null || downloadDir.equals("")){
downloadDir = "down_loads";
}
if (extension == null || extension.equals("")){
extension = "";
}
if (name == null){
return FileUtil.writeToDisk(is,downloadDir,extension.toUpperCase(),extension);
}else {
return FileUtil.writeToDisk(is, downloadDir, name);
}
}
5、拦截器功能的实现--OKHttp中拦截器的改写
如果请求的url中包含参数,进行拦截,改写Response。
5.1 拦截器初始化
位于latte-core模块下的Configurator。
主要作用:传入拦截器,进行初始化。
public final Configurator withInterceptor(Interceptor interceptor) {
INTERCEPTORS.add(interceptor);
LATTE_CONFIGS.put(ConfigKeys.INTERCEPTOR, INTERCEPTORS);
return this;
}
public final Configurator withInterceptors(ArrayList<Interceptor> interceptors) {
INTERCEPTORS.addAll(interceptors);
LATTE_CONFIGS.put(ConfigKeys.INTERCEPTOR, INTERCEPTORS);
return this;
}
5.2 拦截器功能实现
位于latte-core模块下的DebugInterceptor,继承自BaseInterceptor,继承自Interceptor。
主要作用:根据传入参数,如果请求的url中包含参数,进行拦截,更改返回体。
public DebugInterceptor(String debugUrl, int rawId) {
DEBUG_URL = debugUrl;
DEBUG_RAW_ID = rawId;
}
private Response getResponse(Chain chain, String json){
return new Response.Builder()//更改返回体
.code(200)
.addHeader("Content-Type","application/json")
.body(ResponseBody.create(MediaType.parse("application/json"),json))
.message("OK")
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.build();
}
private Response debugResponse(Chain chain, @RawRes int rawId){
final String json = FileUtil.getRawFile(rawId);//将要返回的内容转为json格式
return getResponse(chain, json);
}
@Override
public Response intercept(Chain chain) throws IOException {
final String url = chain.request().url().toString();
if (url.contains(DEBUG_URL)){//请求的url中包含参数
return debugResponse(chain, DEBUG_RAW_ID);
}
return chain.proceed(chain.request());
}