本文只是为了方便自己使用,是根据慕课网上的《Android通用框架设计与完整电商App开发》编写的

引用:

//网络依赖    api 'com.squareup.okio:okio:1.14.1'    api 'com.squareup.okhttp3:okhttp:3.10.0'    api 'com.squareup.retrofit2:retrofit:2.4.0'    api 'com.squareup.retrofit2:converter-scalars:2.4.0'

目录结构:

一、最终调用:建造者模式,书写比较方便,逻辑比较清楚,易于扩展,并且不需要客户知道具体的过程

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

private void testRestClient(){        RestClient.builder()                .url("https://news.baidu.com/")                .loader(getContext())                .success(new ISuccess() {                    @Override                    public void onSuccess(String response) {                        Toast.makeText(getContext(),response,Toast.LENGTH_LONG).show();                    }                })                .failure(new IFailure() {                    @Override                    public void onFailure() {                        Toast.makeText(getContext(), "onFailure",Toast.LENGTH_LONG).show();                    }                }).error(new IError() {            @Override            public void onError(int code, String msg) {                Toast.makeText(getContext(),"onError",Toast.LENGTH_LONG).show();            }        }).build()        .get();    }

二、Retrofit封装

RestService:接口

public interface RestService {    @GET    Call get(@Url String url, @QueryMap Map params);    @FormUrlEncoded    @POST    Call post(@Url String url, @FieldMap Map params);    @POST    Call postRaw(@Url String url, @Body RequestBody body);    @FormUrlEncoded    @PUT    Call put(@Url String url, @FieldMap Map params);    @PUT    Call putRaw(@Url String url, @Body RequestBody body);    @DELETE    Call delete(@Url String url, @QueryMap Map params);    @Streaming    @GET    Call download(@Url String url, @QueryMap Map params);    @Multipart    @POST    Call upload(@Url String url, @Part MultipartBody.Part file);}

在这里并没有将Url直接放在注解上,而是作为一个参数传入方法中,这样的话作为框架比较通用

RestCreator

public class RestCreator {    private static final class ParamsHolder {        public static final WeakHashMap PARAMS = new WeakHashMap<>();    }    public static WeakHashMap getParams () {        return ParamsHolder.PARAMS;    }    public static RestService getRestService() {        return RestServiceHolder.REST_SERVICE;    }    private static final class RetrofitHolder {        private static final String BASE_URL = (String) Latte.getConfigurations().get(ConfigType.API_HOST.name());        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);    }}

在这里初始化Retrofit,在这里使用单例模式对Retrofit以及OKHttp进行初始化,单例模式的写法有多种,这里采用了静态内部类的方式
单例的特点

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

静态内部类优点:

1.采用静态内部类的方式,作为单例,直接用classLoader(jvm类加载机制)进行处理异步加锁问题,并减少内存消耗
2.懒加载(饿汉式),即延迟加载。
3.线程安全。

RestClient

public class RestClient {    private final String URL;    private static final WeakHashMap PARAMS = RestCreator.getParams();    private final IRequest REQUEST;    private final ISuccess SUCCESS;    private final IFailure FAILURE;    private final IError ERROR;    private final RequestBody BODY;    private final LoaderStyle LOAD_STYLE;    private final Context CONTEXT;    private final File FILE;    private final String DOWMLOAD_DIR;    private final String EXTENSION;    private final String NAME;    public RestClient(String url,                      Map params,                      IRequest request,                      ISuccess success,                      IFailure failure,                      IError error,                      RequestBody body,                      LoaderStyle loaderStyle,                      Context context,                      File file,                      String downloadDir,                      String extension,                      String name) {        this.URL = url;        PARAMS.putAll(params);        this.REQUEST = request;        this.SUCCESS = success;        this.FAILURE = failure;        this.ERROR = error;        this.BODY = body;        this.LOAD_STYLE = loaderStyle;        this.CONTEXT = context;        this.FILE = file;        this.DOWMLOAD_DIR = downloadDir;        this.EXTENSION = extension;        this.NAME = name;    }    public static RestClientBuilder builder() {        return new RestClientBuilder();    }    private void request(HttpMethod method) {        final RestService service = RestCreator.getRestService();        Call call = null;        if (REQUEST != null) {            REQUEST.onRequestStart();        }        if (LOAD_STYLE != null) {            LatterLoader.showLoading(CONTEXT,LOAD_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 = service.upload(URL,body);                break;            default:                break;        }        if (call != null) {            call.enqueue(getRequestCallbacks());        }    }    private Callback getRequestCallbacks() {        return new RequestCallbacks(REQUEST, SUCCESS, FAILURE, ERROR,LOAD_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 empty");            }            request(HttpMethod.POST_RAW);        }    }    public final void put() {        if (BODY == null) {            request(HttpMethod.PUT);        } else {            if (!PARAMS.isEmpty()) {                throw new RuntimeException("PARAMS must be empty");            }            request(HttpMethod.PUT_RAW);        }    }    public final void delete() {        request(HttpMethod.DELETE);    }    public final void download(){        new DownloadHandler(URL,REQUEST,SUCCESS,FAILURE,ERROR,DOWMLOAD_DIR,EXTENSION,NAME)                    .handlerDownload();    }}

具体的使用过程使用的是建造者模式进行构建

有些情况下需要简化系统结构,可以把Director和抽象建造者进行结合,因此上述RestClient既是指挥者,同时也是建造者,其中的get()、post()等public方法就是对外暴露,供客户端使用的,,当然还有buider()方法返回了具体的RestClientBuilder产品

重点注意下request()方法,这个方法就是编写的真正去请求RestService中的接口以及调用RestCallBack的回调方法的逻辑

RestClientBuilder

public class RestClientBuilder {    private String mUrl;    private static final Map PARAMS = RestCreator.getParams();    private IRequest mIRquest;    private ISuccess mISuccess;    private IFailure mIFailure;    private IError mError;    private RequestBody mBody;    private LoaderStyle mLoaderStyle;    private Context mContext;    private File mFIle;    private  String mDownloadDir;    private  String mExtension;    private  String mName;    RestClientBuilder() {    }    public final RestClientBuilder url(String url) {        this.mUrl = url;        return this;    }    public final RestClientBuilder params(WeakHashMap params) {        PARAMS.putAll(params);        return this;    }    public final RestClientBuilder params(String key,Object value) {        PARAMS.put(key,value);        return this;    }    public final RestClientBuilder request(IRequest iRequest){        this.mIRquest = iRequest;        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 file(File file){        this.mFIle = file;        return this;    }    public final RestClientBuilder file(String file){        this.mFIle = new File(file);        return this;    }    public final RestClientBuilder error(IError iError) {        this.mError = iError;        return this;    }    public final RestClientBuilder loader(Context context,LoaderStyle loaderStyle) {        this.mLoaderStyle = loaderStyle;        this.mContext = context;        return this;    }    public final RestClientBuilder loader(Context context) {        this.mLoaderStyle = LoaderStyle.BallClipRotatePulseIndicator;        this.mContext = context;        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 RestClient build(){        return new RestClient(mUrl,PARAMS,mIRquest,mISuccess,mIFailure,mError,mBody,mLoaderStyle,mContext,mFIle,mDownloadDir,mExtension,mName);    }}

具体的产品生产方法,类似set方法,以及对外暴露产品的方法build()

HttpMethod相关的方法枚举

public enum  HttpMethod {    GET,    POST,    POST_RAW,    PUT,    PUT_RAW,    DELETE,    UPLOAD}

三、Retrofit回调callback相关

IRequest

public interface IRequest {    void onRequestStart();    void onRequestEnd();}

ISuccess

public interface ISuccess {    void onSuccess(String response);}

IFailure

public interface IFailure {    void onFailure();}

IError

public interface IError {    void onError(int code, String msg);}

RequestCallbacks

public class RequestCallbacks implements Callback {    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 loaderStyle) {        this.REQUEST = request;        this.SUCCESS = success;        this.FAILURE = failure;        this.ERROR = error;        this.LOADER_STYLE = loaderStyle;    }    @Override    public void onResponse(Call call, Response 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 call, Throwable t) {        Log.e("response---------------",t.getMessage());        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() {                    LatterLoader.stopLoading();                }            },1000);        }    }}

四、download封装

DownloadHandler

public class DownloadHandler {    private final String URL;    private static final WeakHashMap PARAMS = RestCreator.getParams();    private final IRequest REQUEST;    private final ISuccess SUCCESS;    private final IFailure FAILURE;    private final IError ERROR;    private final String DOWMLOAD_DIR;    private final String EXTENSION;    private final String NAME;    public DownloadHandler(String url,                           IRequest request,                           ISuccess success,                           IFailure failure,                           IError error,                           String downloadDir,                           String extension,                           String name) {        this.URL = url;        this.REQUEST = request;        this.SUCCESS = success;        this.FAILURE = failure;        this.ERROR = error;        this.DOWMLOAD_DIR = downloadDir;        this.EXTENSION = extension;        this.NAME = name;    }    public final void handlerDownload() {        if (REQUEST != null){            REQUEST.onRequestStart();        }        RestCreator.getRestService().download(URL,PARAMS)                .enqueue(new Callback() {                    @Override                    public void onResponse(Call call, Response response) {                       if(response.isSuccessful()) {                           final ResponseBody body = response.body();                           final SaveFileTask task = new SaveFileTask(REQUEST,SUCCESS);                           task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,DOWMLOAD_DIR,                                   EXTENSION,                                   body,                                   NAME);//                        这里一定要判断文件是否下载完成                           if (task.isCancelled()) {                               if(REQUEST != null) {                                   REQUEST.onRequestEnd();                               }                           }                       } else {                           if (ERROR != null) {                               ERROR.onError(response.code(),response.message());                           }                       }                    }                    @Override                    public void onFailure(Call call, Throwable t) {                        if (FAILURE != null) {                            FAILURE.onFailure();                        }                    }                });    }}

上面这是下载的具体使用,这里需要重新启用一个线程去下载,所以用到了AsyncTask
SaveFileTask

public class SaveFileTask extends AsyncTask {    private final IRequest REQUEST;    private final ISuccess SUCCESS;    public SaveFileTask(IRequest request, ISuccess success) {        this.REQUEST = request;        this.SUCCESS = success;    }    @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");            Latte.getApplicationContext().startActivity(install);        }    }}

具体的下载逻辑在这里进行,doInBackground写的下载的线程,onPostExecute返回的主线程,autoInstallApk()安装apk

FileUtil

public final class FileUtil {    //格式化的模板    private static final String TIME_FORMAT = "_yyyyMMdd_HHmmss";    private static final String SDCARD_DIR =            Environment.getExternalStorageDirectory().getPath();    //默认本地上传图片目录    public static final String UPLOAD_PHOTO_DIR =            Environment.getExternalStorageDirectory().getPath() + "/a_upload_photos/";    //网页缓存地址    public static final String WEB_CACHE_DIR =            Environment.getExternalStorageDirectory().getPath() + "/app_web_cache/";    //系统相机目录    public static final String CAMERA_PHOTO_DIR =            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath() + "/Camera/";    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);    }    /**     * @param timeFormatHeader 格式化的头(除去时间部分)     * @param extension        后缀名     * @return 返回时间格式化后的文件名     */    public static String getFileNameByTime(String timeFormatHeader, String extension) {        return getTimeFormatName(timeFormatHeader) + "." + extension;    }    @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;    }    @SuppressWarnings("ResultOfMethodCallIgnored")    public static File createFile(String sdcardDirName, String fileName) {        return new File(createDir(sdcardDirName), fileName);    }    private static File createFileByTime(String sdcardDirName, String timeFormatHeader, String extension) {        final String fileName = getFileNameByTime(timeFormatHeader, extension);        return createFile(sdcardDirName, fileName);    }    //获取文件的MIME    public static String getMimeType(String filePath) {        final String extension = getExtension(filePath);        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);    }    //获取文件的后缀名    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;    }    /**     * 保存Bitmap到SD卡中     *     * @param dir      目录名,只需要写自己的相对目录名即可     * @param compress 压缩比例 100是不压缩,值约小压缩率越高     * @return 返回该文件     */    public static File saveBitmap(Bitmap mBitmap, String dir, int compress) {        final String sdStatus = Environment.getExternalStorageState();        // 检测sd是否可用        if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) {            return null;        }        FileOutputStream fos = null;        BufferedOutputStream bos = null;        File fileName = createFileByTime(dir, "DOWN_LOAD", "jpg");        try {            fos = new FileOutputStream(fileName);            bos = new BufferedOutputStream(fos);            mBitmap.compress(Bitmap.CompressFormat.JPEG, compress, bos);// 把数据写入文件        } catch (FileNotFoundException e) {            e.printStackTrace();        } finally {            try {                if (bos != null) {                    bos.flush();                }                if (bos != null) {                    bos.close();                }                //关闭流                if (fos != null) {                    fos.flush();                }                if (fos != null) {                    fos.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        refreshDCIM();        return fileName;    }    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;    }    /**     * 通知系统刷新系统相册,使照片展现出来     */    private static void refreshDCIM() {        if (Build.VERSION.SDK_INT >= 19) {            //兼容android4.4版本,只扫描存放照片的目录            MediaScannerConnection.scanFile(Latte.getApplicationContext(),                    new String[]{Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath()},                    null, null);        } else {            //扫描整个SD卡来更新系统图库,当文件很多时用户体验不佳,且不适合4.4以上版本            Latte.getApplicationContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" +                    Environment.getExternalStorageDirectory())));        }    }    /**     * 读取raw目录中的文件,并返回为字符串     */    public static String getRawFile(int id) {        final InputStream is = Latte.getApplicationContext().getResources().openRawResource(id);        final BufferedInputStream bis = new BufferedInputStream(is);        final InputStreamReader isr = new InputStreamReader(bis);        final BufferedReader br = new BufferedReader(isr);        final StringBuilder stringBuilder = new StringBuilder();        String str;        try {            while ((str = br.readLine()) != null) {                stringBuilder.append(str);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                br.close();                isr.close();                bis.close();                is.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return stringBuilder.toString();    }    public static void setIconFont(String path, TextView textView) {        final Typeface typeface = Typeface.createFromAsset(Latte.getApplicationContext().getAssets(), path);        textView.setTypeface(typeface);    }    /**     * 读取assets目录下的文件,并返回字符串     */    public static String getAssetsFile(String name) {        InputStream is = null;        BufferedInputStream bis = null;        InputStreamReader isr = null;        BufferedReader br = null;        StringBuilder stringBuilder = null;        final AssetManager assetManager = Latte.getApplicationContext().getAssets();        try {            is = assetManager.open(name);            bis = new BufferedInputStream(is);            isr = new InputStreamReader(bis);            br = new BufferedReader(isr);            stringBuilder = new StringBuilder();            String str;            while ((str = br.readLine()) != null) {                stringBuilder.append(str);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                if (br != null) {                    br.close();                }                if (isr != null) {                    isr.close();                }                if (bis != null) {                    bis.close();                }                if (is != null) {                    is.close();                }                assetManager.close();            } catch (IOException e) {                e.printStackTrace();            }        }        if (stringBuilder != null) {            return stringBuilder.toString();        } else {            return null;        }    }    public static String getRealFilePath(final Context context, final Uri uri) {        if (null == uri) return null;        final String scheme = uri.getScheme();        String data = null;        if (scheme == null)            data = uri.getPath();        else if (ContentResolver.SCHEME_FILE.equals(scheme)) {            data = uri.getPath();        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {            final Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);            if (null != cursor) {                if (cursor.moveToFirst()) {                    final int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);                    if (index > -1) {                        data = cursor.getString(index);                    }                }                cursor.close();            }        }        return data;    }}

更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. android退出系统的绝杀方法
  6. Android(安卓)EditText修改显示方式
  7. Android(安卓)JNI实例代码(一)
  8. Android中级篇之区分系统程序和安装程序
  9. android Service理解

随机推荐

  1. ViewPager无限循环实现画廊式banner
  2. Android下载文件常见错误解决方法
  3. android使用Navigation实现Fragment之间
  4. android利用WebView与JavaScript交互的方
  5. 程序包android.support.annotation不存在
  6. Android(安卓)8.0整体编译成功后使用mmm
  7. 通过Html网页调用本地安卓(android)app
  8. Android监控程序本身被卸载方法汇总
  9. Android(安卓)6.0 RxJava2 + RxPermissio
  10. Android扫码 有仿微信版