Android okhttp 下载文件到指定文件夹带进度更新加7.0适配

项目需求:

从网络下载文件,并且在手机上显示,文件类型目前有doc,docx,pdf,txt

当然小伙伴们可以自行添加,这里用的是android Intent跳转方式解决,主要通过intent找到可以打开的软件,进行阅读。

此时,有人要问了,图呢,图呢,不好意思,并没有做demo,项目中的东西就不方便展示了。

我说一下具体实现思路:

1.使用okhttp进行网络请求

2.将下载的文件放在自己创建的文件夹中

3.在progressDialog中进行下载进度条的更新

4.下载完成后,进行intent跳转

支持原创:http://blog.csdn.net/lhk147852369/article/details/79078010

也就是说。给你一个按钮,你点击后显示progressDialog ,进度在100,点击查看就ok了,页面没什么东西,就不麻烦了。

这就是需要用的下载工具方法

 

 

    /**
     * 下载文件
     *
     * @param fileUrl     文件url
     * @param destFileDir 文件名:test.docx
     */
    public  void downLoadFile(String fileUrl, final String destFileDir, final ReqProgressCallBack callBack) {
//        File dir = new File(FileUtils.getAppDir());
        final File file = new File(FileUtils.getAppDir(), destFileDir);

        if (file.exists() && file.length() > 0) {
            successCallBack((T) file, callBack);
            return;
        }

        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        Request request = new Request.Builder().url(fileUrl).build();
        final Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e(TAG, e.toString());
                failedCallBack("下载失败", callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                try {
                    long total = response.body().contentLength();
                    Log.e(TAG, "total------>" + total);
                    long current = 0;
                    is = response.body().byteStream();
                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1) {
                        current += len;
                        fos.write(buf, 0, len);
                        Log.e(TAG, "current------>" + current);
                        progressCallBack(total, current, callBack);
                    }
                    fos.flush();
                    successCallBack((T) file, callBack);
                } catch (IOException e) {
                    Log.e(TAG, e.toString());
                    failedCallBack("下载失败", callBack);
                } finally {
                    try {
                        if (is != null) {
                            is.close();
                        }
                        if (fos != null) {
                            fos.close();
                        }
                    } catch (IOException e) {
                        Log.e(TAG, e.toString());
                    }
                }
            }
        });
    }

 

回调:

 

 

  

    private Handler okHttpHandler;//全局处理子线程和M主线程通信
    private OkHttpClient mOkHttpClient;//okHttpClient 实例


    * 初始化RequestManager
     */
    public RequestManager(Context context) {
        //初始化OkHttpClient
        mOkHttpClient = new OkHttpClient().newBuilder()
                .connectTimeout(15, TimeUnit.SECONDS)//设置超时时间
                .readTimeout(15, TimeUnit.SECONDS)//设置读取超时时间
                .writeTimeout(30, TimeUnit.SECONDS)//设置写入超时时间
                .build();
        //初始化Handler
        okHttpHandler = new Handler(context.getMainLooper());
    }



 /**
     * 统一同意处理成功信息
     *
     * @param result
     * @param callBack
     * @param 
     */
    private  void successCallBack(final T result, final ReqCallBack callBack) {
        okHttpHandler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    callBack.onReqSuccess(result);
                }
            }
        });
    }

    /**
     * 统一处理失败信息
     *
     * @param errorMsg
     * @param callBack
     * @param 
     */
    private  void failedCallBack(final String errorMsg, final ReqCallBack callBack) {
        okHttpHandler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    callBack.onReqFailed(errorMsg);
                }
            }
        });
    }




    /**
     * 统一处理进度信息
     *
     * @param total    总计大小
     * @param current  当前进度
     * @param callBack
     * @param 
     */
    private  void progressCallBack(final long total, final long current, final ReqProgressCallBack callBack) {
        okHttpHandler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    callBack.onProgress(total, current);
                }
            }
        });
    }

 

ReqProgressCallBack:
 
 
public interface ReqProgressCallBack extends ReqCallBack{ /** * 响应进度更新 */ void onProgress(long total, long current); }
 

ReqCallBack

 
public interface ReqCallBack { /** * 响应成功 */ void onReqSuccess(T result); /** * 响应失败 */ void onReqFailed(String errorMsg); } 

 


接下来就是调用了:

 

首先我先生成一个ProgressDialog 用来显示进度
大家可以在点击文件时 生成
 
private void showProgress() { progressDialog = new ProgressDialog(ContractDetailsActivity.this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 设置水平进度条 progressDialog.setCancelable(false);// 设置是否可以通过点击Back键取消 progressDialog.setCanceledOnTouchOutside(false);// 设置在点击Dialog外是否取消Dialog进度条 progressDialog.setTitle("正在下载"); progressDialog.setMax(100); progressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "点击查看", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (progressDialog.getProgress() == 100) { // 此file为全局变量 主要为了 请求成功后赋值调用 if (mFile != null) { // Log.e("mFile...", "不为空"); toOpenFile(mFile); progressDialog.dismiss(); } } else { ToastUtils.showToast(ContractDetailsActivity.this, "请等待下载完成后查看"); } } }); progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }); progressDialog.show(); }


然后调用请求网络方法:

 
private void requestFile() { RequestManager.getInstance(this).downLoadFile(SysConstant.baseFile + accessName, accessName, new ReqProgressCallBack() { @Override public void onProgress(long total, long current) { progressDialog.setProgress((int) (current/(double)total*100)); if (progressDialog.getProgress() == 100) { progressDialog.setTitle("下载完成"); } } @Override public void onReqSuccess(File result) { Log.e("fileresult====", result.getName()); mFile = result; progressDialog.setProgress(100); progressDialog.setTitle("下载完成"); } @Override public void onReqFailed(String errorMsg) { Log.e("onReqFailed", errorMsg + " "); progressDialog.setTitle("下载失败,请重新下载..."); } }); }


嗯哼,去用意图打开 你所现在的文件。

accessName是你从网络获取的文件名,我们首先获取文件名,在找到后缀
通过后缀进行判断
 
private void toOpenFile(File file) { Intent intent = null; String end = accessName.substring(accessName.lastIndexOf(".") + 1, accessName.length()).toLowerCase(); Log.e("end", end); if (end.equals("doc") || end.equals("docx")) { // Log.e("intent,file", file.getAbsolutePath()); intent = FileUtils.getWordFileIntent(this, file); } else if (end.equals("pdf")) { intent = FileUtils.getPdfFileIntent(this, file); } else if (end.equals("txt")) { intent = FileUtils.getTextFileIntent(this, file); } else { ToastUtils.showToast(this, "文件类型不支持..."); return; } if (intent != null) { startActivity(intent); } else { ToastUtils.showToast(this, "未找到匹配的程序... "); } }


FileUtils类

这里有写好的 调用系统获取文件的方法。
getPath  主要传的是onActivityResult返回的data。getData()
 
public class FileUtils { /** * 获取对应文件的Uri * * @param intent 相应的Intent * @param file 文件对象 * @return */ private static Uri getUri(Context mContext, Intent intent, File file) { Uri uri = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本是否在7.0以上 // Log.e("packgame", mContext.getPackageName()); uri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".fileprovider", file); //添加这一句表示对目标应用临时授权该Uri所代表的文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { uri = Uri.fromFile(file); } return uri; } public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority()); } public static String getAppDir() { return Environment.getExternalStorageDirectory() + SysConstant.fileName; } public static String getLogDir() { String dir = getAppDir() + "/Log/"; return mkdirs(dir); } private static String mkdirs(String dir) { File file = new File(dir); if (!file.exists()) { file.mkdirs(); } return dir; } //kb 转换 public static String FormetFileSize(long fileS) { DecimalFormat df = new DecimalFormat("#.00"); String fileSizeString = ""; String wrongSize = "0B"; if (fileS == 0) { return wrongSize; } if (fileS < 1024) { fileSizeString = df.format((double) fileS) + "B"; } else if (fileS < 1048576) { fileSizeString = df.format((double) fileS / 1024) + "KB"; } else if (fileS < 1073741824) { fileSizeString = df.format((double) fileS / 1048576) + "MB"; } else { fileSizeString = df.format((double) fileS / 1073741824) + "GB"; } return fileSizeString; } //android获取一个用于打开PDF文件的intent public static Intent getPdfFileIntent(Context context, File file) { Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri uri = getUri(context, intent, file); intent.setDataAndType(uri, "application/pdf"); if (isIntentAvailable(context, intent)) { return intent; } else { return null; } } //android获取一个用于打开文本文件的intent public static Intent getTextFileIntent(Context context, File file) { Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri uri = getUri(context, intent, file); intent.setDataAndType(uri, "text/plain"); if (isIntentAvailable(context, intent)) { return intent; } else { return null; } } //android获取一个用于打开Word文件的intent public static Intent getWordFileIntent(Context context, File file) { Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri uri = getUri(context, intent, file); intent.setDataAndType(uri, "application/msword"); if (isIntentAvailable(context, intent)) { return intent; } else { return null; } } @RequiresApi(api = Build.VERSION_CODES.KITKAT) public static String getPath(Context context, Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;//sdk版本是否大于4.4 // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } // TODO handle non-primary volumes } else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[]{ split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { // Return the remote address if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; final String[] projection = {column}; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { final int index = cursor.getColumnIndexOrThrow(column); return cursor.getString(index); } } finally { if (cursor != null) cursor.close(); } return null; } /** * 判断Intent 是否存在 防止崩溃 * * @param context * @param intent * @return */ private static boolean isIntentAvailable(Context context, Intent intent) { PackageManager packageManager = context.getPackageManager(); if (intent.resolveActivity(packageManager) != null) { return true; } return false; } }


然后,我们要进行android 7.0的适配了,当然 你们不适配也是可以的,

在我的fileUtil类中 把 判断给去掉就可以了
主要是getUri这个方法
 
适配:
注册文件中:
添加provider
applicationId是build.gradle中的defaultConfig中的属性值
主要是包名,你们还可以这样写
authorities="com.ceshi.simple.fileprovider"
这个属性一定要和fileutils中的getUri方法中
uri=FileProvider.getUri(mContext,mContext.getPackName()+".fileprovider",file)
红色标注一模一样 否则会报错的
 
  


在res包中 新建xml包 在xml包中新建file_paths 名字一致就可以了



    
        
    

这个东西你们可以百度 详情一下7.0适配问题,我记不住 就懒得注释说明了

 
以上ok。

 

 

你可能感兴趣的:(Android)