最近一个小伙伴问我有关retrofit的用法,关于这个网络请求框架的内部暂且不讨论,因为除了它是基于okhttp编写的,我也是一无所知。不过用一用还是可以的,所以这里我贴出一个也是最近学习的封装好的代码,以供自己和他人使用。希望方便大家。
1.依赖包
//网络请求依赖
compile 'com.squareup.okio:okio:1.13.0'
compile 'com.squareup.okhttp3:okhttp:3.8.1'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
//Loading依赖
compile 'com.wang.avi:library:2.1.3'
2.style文件加载框样式
<style name="dialog" parent="@android:style/Theme.Dialog">
<!-- 去掉边框-->
<item name="android:windowFrame">@null</item>
<!-- 悬浮-->
<item name="android:windowIsFloating">true</item>
<!-- 半透明-->
<item name="android:windowIsTranslucent">false</item>
<!-- 不需要标题-->
<item name="android:windowNoTitle">true</item>
<!-- 背景透明-->
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 允许模糊-->
<item name="android:backgroundDimEnabled">true</item>
<!-- 全屏幕-->
<item name="android:windowFullscreen">true</item>
</style>
3.目录结构
- net
- callback
- IError.java
- IFailure.java
- IRequest.java
- ISuccess.java
- RequestCallbacks.java
- download
- DownloadHandler.java
- SaveFileTask.java
- Constant.java
- HttpMethod.java
- RestClient.java
- RestClientBuilder.java
- RestCreator.java
- RestService.java
- callback
- ui
- LatteLoader.java
- LoaderCreator.java
- LoaderStyle.java
- util
- DimenUtil.java
- FileUtil.java
4.IError.java
public interface IError {
void onError(int code,String msg);
}
5.IFailure.java
public interface IFailure {
void onFailure();
}
6.IRequest.java
public interface IRequest {
void onRequestStart();
void onRequestEnd();
}
7.ISuccess.java
public interface ISuccess {
void onSuccess(String response);
}
8.RequestCallbacks.java
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;
private static final Handler HANDLER = new Handler();
public RequestCallbacks(IRequest request, ISuccess success, IFailure failure, IError error,LoaderStyle style) {
this.REQUEST = request;
this.SUCCESS = success;
this.FAILURE = failure;
this.ERROR = error;
this.LOADER_STYLE = style;
}
@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();
}
private void stopLoading(){
if (LOADER_STYLE!=null){
HANDLER.postDelayed(new Runnable() {
@Override
public void run() {
LatteLoader.stopLoading();
}
},1000);
}
}
}
9.DownloadHandler.java
public class DownloadHandler {
private final String URL;
private static final WeakHashMap<String, Object> PARAMS = RestCreator.getParams();
private final IRequest IREQUEST;
private final String DOWNLOAD_DIR;
private final String EXTENSION;
private final String NAME;
private final ISuccess ISUCCESS;
private final IFailure IFAILURE;
private final IError IERROR;
private Context context;
public DownloadHandler(Context context, String url, IRequest request, String download_dir, String extension, String name,
ISuccess success, IFailure failure, IError error) {
this.URL = url;
this.IREQUEST = request;
this.DOWNLOAD_DIR = download_dir;
this.EXTENSION = extension;
this.NAME = name;
this.ISUCCESS = success;
this.IFAILURE = failure;
this.IERROR = error;
this.context = context;
}
public final void handleDownload() {
if (IREQUEST != null) {
IREQUEST.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(context, IREQUEST, ISUCCESS);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, DOWNLOAD_DIR, EXTENSION, responseBody, NAME);
//这里一定要注意判断,否则文件下载不全
if (task.isCancelled()) {
if (IREQUEST != null) {
IREQUEST.onRequestEnd();
}
}
} else {
if (IERROR != null) {
IERROR.onError(response.code(), response.message());
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
if (IFAILURE!=null){
IFAILURE.onFailure();
}
}
});
}
}
10.SaveFileTask.java
public class SaveFileTask extends AsyncTask<Object,Void,File>{
private final IRequest REQUEST;
private final ISuccess SUCCESS;
private Context context;
public SaveFileTask(Context context,IRequest REQUEST, ISuccess SUCCESS) {
this.REQUEST = REQUEST;
this.SUCCESS = SUCCESS;
this.context = context;
}
@Override
protected File doInBackground(Object... params) {
String downloadDir = (String) params[0];
String extension = (String) params[1];
final ResponseBody body = (ResponseBody) params[2];
final String name = (String) params[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);
}
}
@Override
protected void onPostExecute(File file) {
super.onPostExecute(file);
if (SUCCESS!=null){
SUCCESS.onSuccess(file.getPath());
}
if (REQUEST!=null){
REQUEST.onRequestEnd();
}
autoInstallApk(file);
}
private void autoInstallApk(File file){
if (FileUtil.getExtension(file.getPath()).equals("apk")){
final Intent install = new Intent();
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.setAction(Intent.ACTION_VIEW);
install.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
context.startActivity(install);
}
}
}
11.Constant.java
public class Constant {
public static final String BASE_URL = "http://www.baidu.com";
}
12.HttpMethod.java
public enum HttpMethod {
GET,
POST,
POST_RAW,
PUT,
PUT_RAW,
DELETE,
UPLOAD
}
13.RestClient.java
public class RestClient {
private final String URL;
private static final WeakHashMap<String, Object> PARAMS = RestCreator.getParams();
private final IRequest IREQUEST;
private final String DOWNLOAD_DIR;
private final String EXTENSION;
private final String NAME;
private final ISuccess ISUCCESS;
private final IFailure IFAILURE;
private final IError IERROR;
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 iRequest, ISuccess iSuccess, IFailure iFailure,
IError iError, RequestBody body, File file,Context context, LoaderStyle loaderStyle,String download_dir,String extension,String name) {
this.URL = url;
PARAMS.putAll(params);
this.IREQUEST = iRequest;
this.ISUCCESS = iSuccess;
this.IFAILURE = iFailure;
this.IERROR = iError;
this.BODY = body;
this.FILE = file;
this.CONTEXT = context;
this.LOADER_STYLE = loaderStyle;
this.DOWNLOAD_DIR = download_dir;
this.EXTENSION = extension;
this.NAME = name;
}
public static RestClientBuilder builder() {
return new RestClientBuilder();
}
private void request(HttpMethod method) {
final RestService service = RestCreator.getRestService();
Call<String> call = null;
if (IREQUEST != null) {
IREQUEST.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());
}
}
private Callback<String> getRequestCallback() {
return new RequestCallbacks(
IREQUEST,
ISUCCESS,
IFAILURE,
IERROR,
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);
}
public final void download(){
new DownloadHandler(CONTEXT,URL,IREQUEST,DOWNLOAD_DIR,EXTENSION,NAME,ISUCCESS,IFAILURE,IERROR).handleDownload();
}
}
14.RestClientBuilder.java
public class RestClientBuilder {
private String mUrl = null;
private static final WeakHashMap<String,Object> PARAMS = RestCreator.getParams();
private IRequest mIRequest = null;
private ISuccess mISuccess = null;
private IFailure mIFailure = null;
private IError mIError = null;
private RequestBody mBody = null;
private Context mContext = null;
private LoaderStyle mLoaderStyle = null;
private File mFile = null;
private String download_dir;
private String extension;
private String name;
/**
* 只允许同包创建类实例
*/
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 success(ISuccess iSuccess){
this.mISuccess = iSuccess;
return this;
}
public final RestClientBuilder failure(IFailure iFailure){
this.mIFailure = iFailure;
return this;
}
public final RestClientBuilder onRequest(IRequest iRequest){
this.mIRequest = iRequest;
return this;
}
public final RestClientBuilder error(IError iError){
this.mIError = iError;
return this;
}
public final RestClientBuilder downloadDir(String download_dir){
this.download_dir = download_dir;
return this;
}
public final RestClientBuilder extension(String extension){
this.extension = extension;
return this;
}
public final RestClientBuilder name(String name){
this.name = name;
return this;
}
public final RestClient build(){
return new RestClient(mUrl,PARAMS,mIRequest,mISuccess,mIFailure,mIError,mBody,mFile,mContext,mLoaderStyle,download_dir,extension,name);
}
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.BallClipRotatePulseIndicator;
return this;
}
}
15.RestCreator.java
public class RestCreator {
private static final class ParamsHolder{
public static final WeakHashMap<String,Object> PARAMS = new WeakHashMap<>();
}
public static WeakHashMap<String,Object> getParams(){
return ParamsHolder.PARAMS;
}
public static RestService getRestService(){
return RestServiceHolder.REST_SERVICE;
}
private static final class RetrofitHolder{
private static final String BASE_URL = Constant.BASE_URL;
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_CLIENT.create(RestService.class);
}
}
16.RestService.java
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);
}
17.LatteLoader.java
public class LatteLoader {
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.BallClipRotatePulseIndicator.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(context);
int deviceHeight = DimenUtil.getScreenHeight(context);
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.isShowing()) {
dialog.cancel();
}
}
}
}
public static void showLoading(Context context,Enum<LoaderStyle> type){
showLoading(context,type.name());
}
}
18.LoaderCreator.java
public final class LoaderCreator {
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);
try {
final Class<?> drawableClass = Class.forName(drawableClassName.toString());
return (Indicator) drawableClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
19.LoaderStyle.java
public enum LoaderStyle {
BallPulseIndicator,
BallGridPulseIndicator,
BallClipRotateIndicator,
BallClipRotatePulseIndicator,
SquareSpinIndicator,
BallClipRotateMultipleIndicator,
BallPulseRiseIndicator,
BallRotateIndicator,
CubeTransitionIndicator,
BallZigZagIndicator,
BallZigZagDeflectIndicator,
BallTrianglePathIndicator,
BallScaleIndicator,
LineScaleIndicator,
LineScalePartyIndicator,
BallScaleMultipleIndicator,
BallPulseSyncIndicator,
BallBeatIndicator,
LineScalePulseOutIndicator,
LineScalePulseOutRapidIndicator,
BallScaleRippleIndicator,
BallScaleRippleMultipleIndicator,
BallSpinFadeLoaderIndicator,
LineSpinFadeLoaderIndicator,
TriangleSkewSpinIndicator,
PacmanIndicator,
BallGridBeatIndicator,
SemiCircleSpinIndicator
}
20.DimenUtil.java
public class DimenUtil {
public static int getScreenWidth(Context context){
final Resources resources = context.getResources();
final DisplayMetrics dm = resources.getDisplayMetrics();
return dm.widthPixels;
}
public static int getScreenHeight(Context context){
final Resources resources = context.getResources();
final DisplayMetrics dm = resources.getDisplayMetrics();
return dm.heightPixels;
}
}
21.FileUtil.java
public class FileUtil {
private static final String SDCARD_DIR = Environment.getExternalStorageDirectory().getPath();
//格式化的模板
private static final String TIME_FORMAT = "_yyyyMMdd_HHmmss";
public static File writeToDisk(InputStream is, String dir, String name) {
final File file = FileUtil.createFile(dir, name);
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(is);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
byte data[] = new byte[1024 * 4];
int count;
while ((count = bis.read(data)) != -1) {
bos.write(data, 0, count);
}
bos.flush();
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bos != null) {
bos.close();
}
if (fos != null) {
fos.close();
}
if (bis != null) {
bis.close();
}
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
public static File writeToDisk(InputStream is, String dir, String prefix, String extension) {
final File file = FileUtil.createFileByTime(dir, prefix, extension);
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(is);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
byte data[] = new byte[1024 * 4];
int count;
while ((count = bis.read(data)) != -1) {
bos.write(data, 0, count);
}
bos.flush();
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bos != null) {
bos.close();
}
if (fos != null) {
fos.close();
}
if (bis != null) {
bis.close();
}
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static File createFile(String sdcardDirName, String fileName) {
return new File(createDir(sdcardDirName), fileName);
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private static File createDir(String sdcardDirName) {
//拼接成SD卡中完整的dir
final String dir = SDCARD_DIR + "/" + sdcardDirName + "/";
final File fileDir = new File(dir);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
return fileDir;
}
private static File createFileByTime(String sdcardDirName, String timeFormatHeader, String extension) {
final String fileName = getFileNameByTime(timeFormatHeader, extension);
return createFile(sdcardDirName, fileName);
}
/**
* @param timeFormatHeader 格式化的头(除去时间部分)
* @param extension 后缀名
* @return 返回时间格式化后的文件名
*/
public static String getFileNameByTime(String timeFormatHeader, String extension) {
return getTimeFormatName(timeFormatHeader) + "." + extension;
}
private static String getTimeFormatName(String timeFormatHeader) {
final Date date = new Date(System.currentTimeMillis());
//必须要加上单引号
final SimpleDateFormat dateFormat = new SimpleDateFormat("'" + timeFormatHeader + "'" + TIME_FORMAT, Locale.getDefault());
return dateFormat.format(date);
}
//获取文件的后缀名
public static String getExtension(String filePath) {
String suffix = "";
final File file = new File(filePath);
final String name = file.getName();
final int idx = name.lastIndexOf('.');
if (idx > 0) {
suffix = name.substring(idx + 1);
}
return suffix;
}
}
22.调用
RestClient.builder()
.url("http://192.168.123.1:8080/firstweb/HelloServlet")
.params("username","123")
.loader(this)
.success(new ISuccess() {
@Override
public void onSuccess(String response) {
Toast.makeText(MainActivity.this,response,Toast.LENGTH_SHORT).show();
}
})
.failure(new IFailure() {
@Override
public void onFailure() {
Toast.makeText(MainActivity.this,"失败",Toast.LENGTH_SHORT).show();
}
})
.error(new IError() {
@Override
public void onError(int code, String msg) {
Toast.makeText(MainActivity.this,"错误",Toast.LENGTH_SHORT).show();
}
})
.build()
.get();