Android中如何下载文件并显示下载进度
2014-12-02 22:16
274 查看
原文地址:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1125/2057.html
这里主要讨论三种方式:AsyncTask、Service和使用DownloadManager。
一、使用AsyncTask并在进度对话框中显示下载进度
这种方式的优势是你可以在后台执行下载任务的同时,也可以更新UI(这里我们用progress bar来更新下载进度)
下面的代码是使用的例子
上面的代码只包含了
注意需要添加如下权限:
二、在service中执行下载
在service中执行下载任务的麻烦之处在于如何通知activity更新UI。下面的代码中我们将用
注册
activity中这样调用
使用ResultReceiver接收来自
三、使用
其实这才是解决下载问题的终极方法,因为他使用起来实在是太简单了。可惜只有在GingerBread 之后才能使用。
先判断能不能使用DownloadManager:
如果能,那么只需要这样就可以开始下载一个文件了:
下载的进度会在消息通知中显示。
总结
前两种方法需要你考虑的东西很多,除非是你想完全控制下载的整个过程,否则用最后一种比较省事。
Demo下载
这里主要讨论三种方式:AsyncTask、Service和使用DownloadManager。
一、使用AsyncTask并在进度对话框中显示下载进度
这种方式的优势是你可以在后台执行下载任务的同时,也可以更新UI(这里我们用progress bar来更新下载进度)
下面的代码是使用的例子
// declare the dialog as a member field of your activity ProgressDialog mProgressDialog; // instantiate it within the onCreate method mProgressDialog = new ProgressDialog(YourActivity.this); mProgressDialog.setMessage("A message"); mProgressDialog.setIndeterminate(true); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setCancelable(true); // execute this when the downloader must be fired final DownloadTask downloadTask = new DownloadTask(YourActivity.this); downloadTask.execute("the url to the file you want to download"); mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { downloadTask.cancel(true); } });
DownloadTask继承自AsyncTask,按照如下框架定义,你需要将代码中的某些参数替换成你自己的。
// usually, subclasses of AsyncTask are declared inside the activity class. // that way, you can easily modify the UI thread from here private class DownloadTask extends AsyncTask<String, Integer, String> { private Context context; private PowerManager.WakeLock mWakeLock; public DownloadTask(Context context) { this.context = context; } @Override protected String doInBackground(String... sUrl) { InputStream input = null; OutputStream output = null; HttpURLConnection connection = null; try { URL url = new URL(sUrl[0]); connection = (HttpURLConnection) url.openConnection(); connection.connect(); // expect HTTP 200 OK, so we don't mistakenly save error report // instead of the file if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { return "Server returned HTTP " + connection.getResponseCode() + " " + connection.getResponseMessage(); } // this will be useful to display download percentage // might be -1: server did not report the length int fileLength = connection.getContentLength(); // download the file input = connection.getInputStream(); output = new FileOutputStream("/sdcard/file_name.extension"); byte data[] = new byte[4096]; long total = 0; int count; while ((count = input.read(data)) != -1) { // allow canceling with back button if (isCancelled()) { input.close(); return null; } total += count; // publishing the progress.... if (fileLength > 0) // only if total length is known publishProgress((int) (total * 100 / fileLength)); output.write(data, 0, count); } } catch (Exception e) { return e.toString(); } finally { try { if (output != null) output.close(); if (input != null) input.close(); } catch (IOException ignored) { } if (connection != null) connection.disconnect(); } return null; }
上面的代码只包含了
doInBackground,这是执行后台任务的代码块,不能在这里做任何的UI操作,但是
onProgressUpdate和onPreExecute是运行在UI线程中的,所以我们应该在这两个方法中更新progress bar。
接上面的代码:
@Override protected void onPreExecute() { super.onPreExecute(); // take CPU lock to prevent CPU from going off if the user // presses the power button during download PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName()); mWakeLock.acquire(); mProgressDialog.show(); } @Override protected void onProgressUpdate(Integer... progress) { super.onProgressUpdate(progress); // if we get here, length is known, now set indeterminate to false mProgressDialog.setIndeterminate(false); mProgressDialog.setMax(100); mProgressDialog.setProgress(progress[0]); } @Override protected void onPostExecute(String result) { mWakeLock.release(); mProgressDialog.dismiss(); if (result != null) Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show(); else Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show(); }
注意需要添加如下权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
二、在service中执行下载
在service中执行下载任务的麻烦之处在于如何通知activity更新UI。下面的代码中我们将用
ResultReceiver
和IntentService来实现下载。
ResultReceiver允许我们接收来自service中发出的广播,
IntentService继承自service,这
IntentService中我们开启一个线程开执行下载任务(service和你的app其实是在一个线程中,因此不想阻塞主线程的话必须开启新的线程)。
public class DownloadService extends IntentService { public static final int UPDATE_PROGRESS = 8344; public DownloadService() { super("DownloadService"); } @Override protected void onHandleIntent(Intent intent) { String urlToDownload = intent.getStringExtra("url"); ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver"); try { URL url = new URL(urlToDownload); URLConnection connection = url.openConnection(); connection.connect(); // this will be useful so that you can show a typical 0-100% progress bar int fileLength = connection.getContentLength(); // download the file InputStream input = new BufferedInputStream(connection.getInputStream()); OutputStream output = new FileOutputStream("/sdcard/BarcodeScanner-debug.apk"); byte data[] = new byte[1024]; long total = 0; int count; while ((count = input.read(data)) != -1) { total += count; // publishing the progress.... Bundle resultData = new Bundle(); resultData.putInt("progress" ,(int) (total * 100 / fileLength)); receiver.send(UPDATE_PROGRESS, resultData); output.write(data, 0, count); } output.flush(); output.close(); input.close(); } catch (IOException e) { e.printStackTrace(); } Bundle resultData = new Bundle(); resultData.putInt("progress" ,100); receiver.send(UPDATE_PROGRESS, resultData); } }
注册
DownloadService:
<service android:name=".DownloadService"/>
activity中这样调用
DownloadService
// initialize the progress dialog like in the first example // this is how you fire the downloader mProgressDialog.show(); Intent intent = new Intent(this, DownloadService.class); intent.putExtra("url", "url of the file to download"); intent.putExtra("receiver", new DownloadReceiver(new Handler())); startService(intent);
使用ResultReceiver接收来自
DownloadService的下载进度通知
private class DownloadReceiver extends ResultReceiver{ public DownloadReceiver(Handler handler) { super(handler); } @Override protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); if (resultCode == DownloadService.UPDATE_PROGRESS) { int progress = resultData.getInt("progress"); mProgressDialog.setProgress(progress); if (progress == 100) { mProgressDialog.dismiss(); } } } }
三、使用
DownloadManager
其实这才是解决下载问题的终极方法,因为他使用起来实在是太简单了。可惜只有在GingerBread 之后才能使用。
先判断能不能使用DownloadManager:
/** * @param context used to check the device version and DownloadManager information * @return true if the download manager is available */ public static boolean isDownloadManagerAvailable(Context context) { try { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) { return false; } Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setClassName("com.android.providers.downloads.ui", "com.android.providers.downloads.ui.DownloadList"); List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; } catch (Exception e) { return false; } }
如果能,那么只需要这样就可以开始下载一个文件了:
String url = "url you want to download"; DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setDescription("Some descrition"); request.setTitle("Some title"); // in order for this if to run, you must use the android 3.2 to compile your app if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); } request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext"); // get download service and enqueue file DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); manager.enqueue(request);
下载的进度会在消息通知中显示。
总结
前两种方法需要你考虑的东西很多,除非是你想完全控制下载的整个过程,否则用最后一种比较省事。
Demo下载
相关文章推荐
- android中如何下载文件并显示下载进度
- android中如何下载文件并显示下载进度
- 用idhttp打开网页或下载文件时如何显示进度
- NSURLConnection下载文件时,如何显示进度
- Android 下载网络url文件并显示进度
- Android开发之文件下载(通知栏中显示进度条,状态信息等)
- Android 下载文件 显示进度条
- Android 下载文件 显示进度条
- Android中AsyncTask进行后台下载文件并在下拉菜单显示下载进度
- Android 下载文件并显示进度条
- Android实现Service下载文件,Notification显示下载进度
- android文件下载及自定义通知显示下载进度
- Android 下载文件 显示进度条
- Android实现Service下载文件,Notification显示下载进度的示例
- Android开发之文件下载,状态时显示下载进度,点击自动安装
- Android中AsyncTask进行后台下载文件并在下拉菜单显示下载进度
- android+https网址屏蔽证书+IntentService+NotifyManager通知栏+下载apk文件+在通知栏显示下载进度+完成之后提示安装
- android开发教程教您用于下载文件和显示现在进度的线程类
- Android使用ProgressBar、自定义Notification显示文件下载进度
- Android 下载文件 显示进度条