|
| 1 | +## 在Android里面下载文件,并在ProgressDialog显示进度 |
| 2 | + |
| 3 | +### 问题 |
| 4 | +尝试写一个可以获得更新的应用程序。 为了达到这个效果,我写了一个可以下载文件并且在一个`ProgressDialog`里面显示进度的简单方法。我知道怎么使用`ProgressDialog`,但是我不太确定怎么显示当前进度和下载文件。 |
| 5 | + |
| 6 | +### 回答 |
| 7 | + |
| 8 | +有很多方式去下载文件。我给出一些最常用的方法;由你来选择选择哪一个最适合你的应用。 |
| 9 | + |
| 10 | +#### 1. 使用AsyncTask,并且在一个dialog里面显示进度 |
| 11 | +这种方法允许你执行一些后台任务,并且同时更新UI(在这里,我们是更新进度条progress bar)。 |
| 12 | + |
| 13 | +首先是实例代码 |
| 14 | +```java |
| 15 | +// 定义一个dialog为Activity的成员变量 |
| 16 | +ProgressDialog mProgressDialog; |
| 17 | + |
| 18 | +// 在OnCreate()方法里面初始化 |
| 19 | +mProgressDialog = new ProgressDialog(YourActivity.this); |
| 20 | +mProgressDialog.setMessage("A message"); |
| 21 | +mProgressDialog.setIndeterminate(true); |
| 22 | +mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); |
| 23 | +mProgressDialog.setCancelable(true); |
| 24 | + |
| 25 | +// 执行下载器 |
| 26 | +final DownloadTask downloadTask = new DownloadTask(YourActivity.this); |
| 27 | +downloadTask.execute("你要下载文件的Url"); |
| 28 | + |
| 29 | +mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { |
| 30 | + @Override |
| 31 | + public void onCancel(DialogInterface dialog) { |
| 32 | + downloadTask.cancel(true); |
| 33 | + } |
| 34 | +}); |
| 35 | +``` |
| 36 | + |
| 37 | +`AsyncTask`看起来像这样 |
| 38 | +```java |
| 39 | +// 一般我们把AsyncTask的子类定义在Activity的内部 |
| 40 | +// 通过这种方式,我们就可以轻松地在这里更改UI线程 |
| 41 | +private class DownloadTask extends AsyncTask<String, Integer, String> { |
| 42 | + |
| 43 | + private Context context; |
| 44 | + private PowerManager.WakeLock mWakeLock; |
| 45 | + |
| 46 | + public DownloadTask(Context context) { |
| 47 | + this.context = context; |
| 48 | + } |
| 49 | + |
| 50 | + @Override |
| 51 | + protected String doInBackground(String... sUrl) { |
| 52 | + InputStream input = null; |
| 53 | + OutputStream output = null; |
| 54 | + HttpURLConnection connection = null; |
| 55 | + try { |
| 56 | + URL url = new URL(sUrl[0]); |
| 57 | + connection = (HttpURLConnection) url.openConnection(); |
| 58 | + connection.connect(); |
| 59 | + |
| 60 | + // 避免因为接收到非HTTP 200 OK状态,而导致只或者错误代码,而不是要下载的文件 |
| 61 | + if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { |
| 62 | + return "Server returned HTTP " + connection.getResponseCode() |
| 63 | + + " " + connection.getResponseMessage(); |
| 64 | + } |
| 65 | + |
| 66 | + // 这对显示下载百分比有帮助 |
| 67 | + // 当服务器没有返回文件的大小时,数字可能为-1 |
| 68 | + int fileLength = connection.getContentLength(); |
| 69 | + |
| 70 | + // 下载文件 |
| 71 | + input = connection.getInputStream(); |
| 72 | + output = new FileOutputStream("/sdcard/file_name.extension"); |
| 73 | + |
| 74 | + byte data[] = new byte[4096]; |
| 75 | + long total = 0; |
| 76 | + int count; |
| 77 | + while ((count = input.read(data)) != -1) { |
| 78 | + // 允许用返回键取消下载 |
| 79 | + if (isCancelled()) { |
| 80 | + input.close(); |
| 81 | + return null; |
| 82 | + } |
| 83 | + total += count; |
| 84 | + // 更新下载进度 |
| 85 | + if (fileLength > 0) // 只有当 fileLength>0 的时候才会调用 |
| 86 | + publishProgress((int) (total * 100 / fileLength)); |
| 87 | + output.write(data, 0, count); |
| 88 | + } |
| 89 | + } catch (Exception e) { |
| 90 | + return e.toString(); |
| 91 | + } finally { |
| 92 | + try { |
| 93 | + if (output != null) |
| 94 | + output.close(); |
| 95 | + if (input != null) |
| 96 | + input.close(); |
| 97 | + } catch (IOException ignored) { |
| 98 | + } |
| 99 | + |
| 100 | + if (connection != null) |
| 101 | + connection.disconnect(); |
| 102 | + } |
| 103 | + return null; |
| 104 | + } |
| 105 | +``` |
| 106 | + |
| 107 | +上面的`doInBackground`方法总是在后台线程中运行。你不能在这里做任何UI线程相关的任务。另一方面,`onProgressUpdate`和`onPreExecute`是在UI线程里面运行的,所以你可以在这里更改进度条。 |
| 108 | + |
| 109 | +```java |
| 110 | +@Override |
| 111 | + protected void onPreExecute() { |
| 112 | + super.onPreExecute(); |
| 113 | + // 取得CPU锁,避免因为用户在下载过程中按了电源键而导致的失效 |
| 114 | + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); |
| 115 | + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, |
| 116 | + getClass().getName()); |
| 117 | + mWakeLock.acquire(); |
| 118 | + mProgressDialog.show(); |
| 119 | + } |
| 120 | + |
| 121 | + @Override |
| 122 | + protected void onProgressUpdate(Integer... progress) { |
| 123 | + super.onProgressUpdate(progress); |
| 124 | + // 如果到了这里,文件长度是确定的,设置indeterminate为false |
| 125 | + mProgressDialog.setIndeterminate(false); |
| 126 | + mProgressDialog.setMax(100); |
| 127 | + mProgressDialog.setProgress(progress[0]); |
| 128 | + } |
| 129 | + |
| 130 | + @Override |
| 131 | + protected void onPostExecute(String result) { |
| 132 | + mWakeLock.release(); |
| 133 | + mProgressDialog.dismiss(); |
| 134 | + if (result != null) |
| 135 | + Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show(); |
| 136 | + else |
| 137 | + Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show(); |
| 138 | + } |
| 139 | +``` |
| 140 | + |
| 141 | +为了可正常运行,你还要取得WAKE_LOCK权限 |
| 142 | +``` |
| 143 | +<uses-permission android:name="android.permission.WAKE_LOCK" /> |
| 144 | +``` |
| 145 | + |
| 146 | +### 从服务器上下载文件 |
0 commit comments