• Android中如何下载文件并显示下载进度


    原文地址:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1125/2057.html

    这里主要讨论三种方式:AsyncTask、Service和使用DownloadManager

    一、使用AsyncTask并在进度对话框中显示下载进度

    这种方式的优势是你可以在后台执行下载任务的同时,也可以更新UI(这里我们用progress bar来更新下载进度)

    下面的代码是使用的例子

     1 // declare the dialog as a member field of your activity
     2 ProgressDialog mProgressDialog;
     3 // instantiate it within the onCreate method
     4 mProgressDialog = new ProgressDialog(YourActivity.this);
     5 mProgressDialog.setMessage("A message");
     6 mProgressDialog.setIndeterminate(true);
     7 mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
     8 mProgressDialog.setCancelable(true);
     9 // execute this when the downloader must be fired
    10 final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
    11 downloadTask.execute("the url to the file you want to download");
    12 mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
    13     @Override
    14     public void onCancel(DialogInterface dialog) {
    15         downloadTask.cancel(true);
    16     }
    17 });

    DownloadTask继承自AsyncTask,按照如下框架定义,你需要将代码中的某些参数替换成你自己的。

     1 // usually, subclasses of AsyncTask are declared inside the activity class.
     2 // that way, you can easily modify the UI thread from here
     3 private class DownloadTask extends AsyncTask<String, Integer, String> {
     4     private Context context;
     5     private PowerManager.WakeLock mWakeLock;
     6     public DownloadTask(Context context) {
     7         this.context = context;
     8     }
     9     @Override
    10     protected String doInBackground(String... sUrl) {
    11         InputStream input = null;
    12         OutputStream output = null;
    13         HttpURLConnection connection = null;
    14         try {
    15             URL url = new URL(sUrl[0]);
    16             connection = (HttpURLConnection) url.openConnection();
    17             connection.connect();
    18             // expect HTTP 200 OK, so we don't mistakenly save error report
    19             // instead of the file
    20             if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
    21                 return "Server returned HTTP " + connection.getResponseCode()
    22                         + " " + connection.getResponseMessage();
    23             }
    24             // this will be useful to display download percentage
    25             // might be -1: server did not report the length
    26             int fileLength = connection.getContentLength();
    27             // download the file
    28             input = connection.getInputStream();
    29             output = new FileOutputStream("/sdcard/file_name.extension");
    30             byte data[] = new byte[4096];
    31             long total = 0;
    32             int count;
    33             while ((count = input.read(data)) != -1) {
    34                 // allow canceling with back button
    35                 if (isCancelled()) {
    36                     input.close();
    37                     return null;
    38                 }
    39                 total += count;
    40                 // publishing the progress....
    41                 if (fileLength > 0) // only if total length is known
    42                     publishProgress((int) (total * 100 / fileLength));
    43                 output.write(data, 0, count);
    44             }
    45         } catch (Exception e) {
    46             return e.toString();
    47         } finally {
    48             try {
    49                 if (output != null)
    50                     output.close();
    51                 if (input != null)
    52                     input.close();
    53             } catch (IOException ignored) {
    54             }
    55             if (connection != null)
    56                 connection.disconnect();
    57         }
    58         return null;
    59     }

    上面的代码只包含了doInBackground,这是执行后台任务的代码块,不能在这里做任何的UI操作,但是onProgressUpdate和onPreExecute是运行在UI线程中的,所以我们应该在这两个方法中更新progress bar。

    接上面的代码:

     1 @Override
     2 protected void onPreExecute() {
     3     super.onPreExecute();
     4     // take CPU lock to prevent CPU from going off if the user
     5     // presses the power button during download
     6     PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
     7     mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
     8          getClass().getName());
     9     mWakeLock.acquire();
    10     mProgressDialog.show();
    11 }
    12 @Override
    13 protected void onProgressUpdate(Integer... progress) {
    14     super.onProgressUpdate(progress);
    15     // if we get here, length is known, now set indeterminate to false
    16     mProgressDialog.setIndeterminate(false);
    17     mProgressDialog.setMax(100);
    18     mProgressDialog.setProgress(progress[0]);
    19 }
    20 @Override
    21 protected void onPostExecute(String result) {
    22     mWakeLock.release();
    23     mProgressDialog.dismiss();
    24     if (result != null)
    25         Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
    26     else
    27         Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
    28 }

    注意需要添加如下权限:

    1 <uses-permission android:name="android.permission.WAKE_LOCK" />

    二、在service中执行下载

    在service中执行下载任务的麻烦之处在于如何通知activity更新UI。下面的代码中我们将用ResultReceiver和IntentService来实现下载。ResultReceiver允许我们接收来自service中发出的广播,IntentService继承自service,这IntentService中我们开启一个线程开执行下载任务(service和你的app其实是在一个线程中,因此不想阻塞主线程的话必须开启新的线程)。

     1 public class DownloadService extends IntentService {
     2     public static final int UPDATE_PROGRESS = 8344;
     3     public DownloadService() {
     4         super("DownloadService");
     5     }
     6     @Override
     7     protected void onHandleIntent(Intent intent) {
     8         String urlToDownload = intent.getStringExtra("url");
     9         ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
    10         try {
    11             URL url = new URL(urlToDownload);
    12             URLConnection connection = url.openConnection();
    13             connection.connect();
    14             // this will be useful so that you can show a typical 0-100% progress bar
    15             int fileLength = connection.getContentLength();
    16             // download the file
    17             InputStream input = new BufferedInputStream(connection.getInputStream());
    18             OutputStream output = new FileOutputStream("/sdcard/BarcodeScanner-debug.apk");
    19             byte data[] = new byte[1024];
    20             long total = 0;
    21             int count;
    22             while ((count = input.read(data)) != -1) {
    23                 total += count;
    24                 // publishing the progress....
    25                 Bundle resultData = new Bundle();
    26                 resultData.putInt("progress" ,(int) (total * 100 / fileLength));
    27                 receiver.send(UPDATE_PROGRESS, resultData);
    28                 output.write(data, 0, count);
    29             }
    30             output.flush();
    31             output.close();
    32             input.close();
    33         } catch (IOException e) {
    34             e.printStackTrace();
    35         }
    36         Bundle resultData = new Bundle();
    37         resultData.putInt("progress" ,100);
    38         receiver.send(UPDATE_PROGRESS, resultData);
    39     }
    40 }

    注册DownloadService

    1 <service android:name=".DownloadService"/>

    activity中这样调用DownloadService

    1 // initialize the progress dialog like in the first example
    2 // this is how you fire the downloader
    3 mProgressDialog.show();
    4 Intent intent = new Intent(this, DownloadService.class);
    5 intent.putExtra("url", "url of the file to download");
    6 intent.putExtra("receiver", new DownloadReceiver(new Handler()));
    7 startService(intent);

    使用ResultReceiver接收来自DownloadService的下载进度通知

     1 private class DownloadReceiver extends ResultReceiver{
     2     public DownloadReceiver(Handler handler) {
     3         super(handler);
     4     }
     5     @Override
     6     protected void onReceiveResult(int resultCode, Bundle resultData) {
     7         super.onReceiveResult(resultCode, resultData);
     8         if (resultCode == DownloadService.UPDATE_PROGRESS) {
     9             int progress = resultData.getInt("progress");
    10             mProgressDialog.setProgress(progress);
    11             if (progress == 100) {
    12                 mProgressDialog.dismiss();
    13             }
    14         }
    15     }
    16 }

    三、使用DownloadManager

    其实这才是解决下载问题的终极方法,因为他使用起来实在是太简单了。可惜只有在GingerBread 之后才能使用。

    先判断能不能使用DownloadManager:

     1 /**
     2  * @param context used to check the device version and DownloadManager information
     3  * @return true if the download manager is available
     4  */
     5 public static boolean isDownloadManagerAvailable(Context context) {
     6     try {
     7         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
     8             return false;
     9         }
    10         Intent intent = new Intent(Intent.ACTION_MAIN);
    11         intent.addCategory(Intent.CATEGORY_LAUNCHER);
    12         intent.setClassName("com.android.providers.downloads.ui", "com.android.providers.downloads.ui.DownloadList");
    13         List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent,
    14                 PackageManager.MATCH_DEFAULT_ONLY);
    15         return list.size() > 0;
    16     } catch (Exception e) {
    17         return false;
    18     }
    19 }

    如果能,那么只需要这样就可以开始下载一个文件了:

     1 String url = "url you want to download";
     2 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
     3 request.setDescription("Some descrition");
     4 request.setTitle("Some title");
     5 // in order for this if to run, you must use the android 3.2 to compile your app
     6 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
     7     request.allowScanningByMediaScanner();
     8     request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
     9 }
    10 request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");
    11 // get download service and enqueue file
    12 DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    13 manager.enqueue(request);

    下载的进度会在消息通知中显示。

    总结

    前两种方法需要你考虑的东西很多,除非是你想完全控制下载的整个过程,否则用最后一种比较省事。

    Demo下载

  • 相关阅读:
    Quick Find
    并查集
    树形问题和更多树
    二叉搜索树的局限性
    Oracle Auto Increment Column
    测试机器性能
    EXP/IMP version
    python getaddrinfo 函数
    open cursor too much error
    要看的一些链接
  • 原文地址:https://www.cnblogs.com/liangstudyhome/p/4138702.html
Copyright © 2020-2023  润新知