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下載
?
轉載于:https://www.cnblogs.com/liangstudyhome/p/4138702.html
總結
以上是生活随笔為你收集整理的Android中如何下载文件并显示下载进度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单的JSON解析工具
- 下一篇: 手摇泵PHP一32_节能手摇泵的制作方法