网络请求框架封装(OkHttp3+Retrofit+loading的封装)
- 本文主要将Retrofit网络请求和loading进行封装,之后只需很少的代码就能实现网络请求he
-
Retrofit的Github链接
点此链接到Github -
AVLoadingIndicatorView的Github链接(封装到请求框架中,请求过程中的loading样式框(不停转的那个))
点此链接到Github
- 封装后进行post请求的效果展示(在任意需要网络请求的地方)
RestClient.builder()
.url("/sign_in")
.loader(getContext())
.params("account", mEmail.getText().toString())
.params("password", mPassword.getText().toString())
.success(new ISuccess(){
@Override
public void onSuccess(){
//请求成功的处理逻辑
}
})
.error(new IError(){
@Override
public void onError(){
//请求错误的处理逻辑
}
})
.failure(new IFailure(){
@override
public void onFailure(){
//请求失败的处理逻辑
}
}
.build()
.post();
- 引入依赖
//网络请求依赖
api 'com.squareup.okio:okio:1.13.0'
api 'com.squareup.okhttp3:okhttp:3.8.1'
api 'com.squareup.retrofit2:retrofit:2.3.0'
api 'com.squareup.retrofit2:converter-scalars:2.3.0'
// loader依赖
api 'com.wang.avi:library:2.1.3'
-
网络框架结构
-
loading封装结构
Loader的封装
1.新建LoaderStyle枚举类即定义loading展示的样式,可以在github上拿到,这里只拉了一部分。
public enum LoaderStyle{
BallPulseIndicator,
BallGridPulseIndicator,
BallClipRotateIndicator,
BallClipRotatePulseIndicator,
SquareSpinIndicator,
BallClipRotateMultipleIndicator,
BallPulseRiseIndicator,
BallRotateIndicator,
CubeTransitionIndicator,
BallZigZagIndicator
}
- 2.新建LoaderCreator类,通过映射,拿到需要的样式图标。
public final class LoaderCreator{
// 优化,新建一个map集合,存储已经映射过的Loading
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;
}
// 得到该type类型的Indicator
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);
try {
final Class<?> drawableClass = Class.forName(drawableClassName.toString());
return (Indicator) drawableClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
- 3.新建MyLoader,通过映射得到的图标,显示到屏幕上。
public class MyLoader{
private static final int LOADER_SIZE_SCALE=8;
private static final int LOADER_OFFSET_SCALE=10;
private static final ArrayList<AppCompatDialog> LOADERS=new ArrayList<>();
private static final String DEFAULT_LOADER=LoaderStyle.BallSpinFadeLoaderIndicator.name();
public static void showLoading(Context context,Enum<LoaderStyle> styleEnum){
showLoading(context,styleEnum.name());
}
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){
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();
}
public static void showLoading(Context context){
showLoading(context,DEFAULT_LOADER);
}
public static void stopLoading(){
for (AppCompatDialog dialog:LOADERS){
if (dialog!=null){
if (dialog!=null){
dialog.cancel();
}
}
}
}
}
RestClient封装
1.先建立Retrofit请求必须要的接口文件RestService(泛式封装)
public interface RestService{
@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);
@FormUrlEncoded
@PUT
Call<String> put(@Url String url, @FieldMap Map<String, Object> params);
@PUT
Call<String> putRaw(@Url String url, @Body RequestBody body);
@DELETE
Call<String> delete(@Url String url, @QueryMap Map<String, Object> params);
@Streaming
@GET
Call<ResponseBody> download(@Url String url, @QueryMap Map<String, Object> params);
@Multipart
@POST
Call<String> upload(@Url String url, @Part MultipartBody.Part file);
}
- 2.新建HttpMethod的枚举类
public enum HttpMethod{
GET,
POST,
POST_RAW,
PUT,
PUT_RAW,
DELETE,
UPLOAD
}
- 3.新建RestCreator类,将RetrofitService的接口实例化,然后用来进行网络请求。(静态内部类实现线程安全的单例模式)
public class RestCreator{
// 参数的单例模式
private static final class ParamsHolder{
private static final WeakHashMap<String, Object> PARAMS = new WeakHashMap<>();
}
public static WeakHashMap<String, Object> getParams(){
return ParamsHolder.PARAMS;
}
// 对外释放RestService的实例
public static RestService getRestService(){
return RestServiceHolder.REST_SRVICE;
}
private static final class RetrofitHolder{
private static final String BASE_URL = "http://www.baidu.com/"
private static final Retrofit RETROFIT_CLIENT = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(OKHttpHolder.OK_HTTP_CLIENT)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
}
private static final class OKHttpHolder {
private static final int TIME_OUT = 60;
private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(TIME_OUT, TimeUnit.SECONDS)
.build();
}
private static final class RestServiceHolder{
private static final RestService REST_SERVICE = RetrofitHolder.RETROFIT_HOLDER.create(RestService.class);
}
}
- 4.根据获取到的参数数据,组装之后进行网络请求(使用建造者模式进行数据的组装)先建立callback的回调接口
public interface ISuccess {
void onSuccess(String response);
}
public interface IError {
void onError(int Code, String msg);
}
public interface IFailure {
void onFailure();
}
public interface IRequest {
void onRequestStart();
void onRequestEnd();
}
- 5.新建RequestCallbacks实现Callback<String>的接口,即处理网络请求的回调
public class RequestCallbacks implements Callback<String>{
private final IRequest REQUEST;
private final ISuccess SUCCESS;
private final IFailure FAILURE;
private final IError ERROR;
private final LoaderStyle LOADER_STYLE;
public RequestCallbacks(IRequest request, ISuccess success, IFailure failure, IError error, LoaderStyle loaderStyle){
this.REQUEST = request;
this.SUCCESS = success;
this.FAILURE = failure;
this.ERROR = error;
this.LOADER_STYLE = loaderStyle;
}
@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());
}
}
stopLoader();
}
@Override
public void onFailure(Call<String> call, Throwable t) {
if (FAILURE != null) {
FAILURE.onFailure();
}
if (REQUEST != null) {
REQUEST.onRequestEnd();
}
stopLoader();
}
private void stopLoader() {
if (LOADER_STYLE != null) {
LatteLoader.stopLoading();
}
}
}
- 6.新建RestClient类,就是将传入的数据进行组装然后用之前实例化的RestService对象进行网络请求。
public class RestClient{
private final String URL;
private static final WeakHashMap<String, Object> PARAMS = RestCreator.getParams();
private final IRequest REQUEST;
private final String DOWNLOAD_DIR;
private final String EXTENSION;
private final String NAME;
private final ISuccess SUCCESS;
private final IFailure FAILURE;
private final IError ERROR;
private final RequestBody BODY;
private final LoaderStyle LOADER_STYLE;
private final File FILE;
private final Context CONTEXT;
public RestClient(String url,
Map<String, Object> params,
IRequest request,
String download_dir,
String extension,
String name,
ISuccess success,
IFailure failure,
IError error,
RequestBody body,
LoaderStyle loaderStyle,
File file,
Context context) {
this.URL = url;
PARAMS.putAll(params);
this.REQUEST = request;
this.DOWNLOAD_DIR = download_dir;
this.EXTENSION = extension;
this.NAME = name;
this.SUCCESS = success;
this.FAILURE = failure;
this.ERROR = error;
this.BODY = body;
this.LOADER_STYLE = loaderStyle;
this.FILE = file;
this.CONTEXT = context;
}
public static RestClientBuilder builder() {
return new RestClientBuilder();
}
private void request(HttpMethod method){
final RestService service = RestCreator.getRestService();
Call<String> call = null;
if(REQUEST != null){
REQUEST.onRequestStart();
}
if (LOADER_STYLE != null) {
LatteLoader.showLoading(CONTEXT, LOADER_STYLE);
}
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);
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());
}
RestCreator.getParams().clear();
}
private Callback<String> getRequestCallback() {
return new RequestCallbacks(
REQUEST,
SUCCESS,
FAILURE,
ERROR,
LOADER_STYLE
);
}
public final void get() {
request(HttpMethod.GET);
}
public final void post() {
if (BODY == null) {
request(HttpMethod.POST);
} else {
if (PARAMS.isEmpty()) {
throw new RuntimeException("params must be null");
}
request(HttpMethod.POST_RAW);
}
}
public final void put() {
if (BODY == null) {
request(HttpMethod.PUT);
} else {
if (PARAMS.isEmpty()) {
throw new RuntimeException("params must be null");
}
request(HttpMethod.PUT_RAW);
}
}
public final void delete() {
request(HttpMethod.DELETE);
}
public final void upload() {
request(HttpMethod.UPLOAD);
}
}
- 7.新建RestClientBuilder,就是RestClient的建造者类
public class RestClientBuilder {
private String mUrl = null;
private static final Map<String, Object> PARAMS = RestCreator.getParams();
private IRequest mIRequest = null;
private String mDownloadDir = null;
private String mExtension = null;
private String mName = null;
private ISuccess mISuccess = null;
private IFailure mIFailure = null;
private IError mIError = null;
private RequestBody mBody = null;
private LoaderStyle mLoaderStyle = null;
private File mFile = null;
private Context mContext = null;
RestClientBuilder() {
}
public final RestClientBuilder url(String url) {
this.mUrl = url;
return this;
}
public final RestClientBuilder params(WeakHashMap<String, Object> params) {
PARAMS.putAll(params);
return this;
}
public final RestClientBuilder params(String key, Object value) {
PARAMS.put(key, value);
return this;
}
public final RestClientBuilder file(File file) {
this.mFile = file;
return this;
}
public final RestClientBuilder file(String file) {
this.mFile = new File(file);
return this;
}
public final RestClientBuilder raw(String raw) {
this.mBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), raw);
return this;
}
public final RestClientBuilder dir(String dir) {
this.mDownloadDir = dir;
return this;
}
public final RestClientBuilder extension(String extension) {
this.mExtension = extension;
return this;
}
public final RestClientBuilder name(String name) {
this.mName = name;
return this;
}
public final RestClientBuilder onRequest(IRequest iRequest) {
this.mIRequest = iRequest;
return this;
}
public final RestClientBuilder success(ISuccess iSuccess) {
this.mISuccess = iSuccess;
return this;
}
public final RestClientBuilder failure(IFailure iFailure) {
this.mIFailure = iFailure;
return this;
}
public final RestClientBuilder error(IError iError) {
this.mIError = iError;
return this;
}
public final RestClientBuilder loader(Context context, LoaderStyle style) {
this.mContext = context;
this.mLoaderStyle = style;
return this;
}
public final RestClientBuilder loader(Context context) {
this.mContext = context;
this.mLoaderStyle = LoaderStyle.BallSpinFadeLoaderIndicator;
return this;
}
public final RestClient build() {
return new RestClient(mUrl, PARAMS, mIRequest, mDownloadDir, mExtension, mName, mISuccess, mIFailure, mIError, mBody, mLoaderStyle, mFile, mContext);
}
}
- 8.小结
至此网络框架告一段落,其中的download没有写全,调用方式就是开头写的那样。