文档章节

Android下载(外文)

蜀山下的鱼
 蜀山下的鱼
发布于 2015/04/29 00:42
字数 1429
阅读 10
收藏 0

There are many ways to download files. Following I will post most common ways; it is up to you to decide which method is better for your app.

1. Use AsyncTask and show the download progress in a dialog

This method will allow you to execute some background processes and update the UI at the same time (in this case, we'll update a progress bar).

This is an example code:

// 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); } });

The AsyncTask will look like this:

// 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; }

The method above (doInBackground) runs always on a background thread. You shouldn't do any UI tasks there. On the other hand, the onProgressUpdate and onPreExecute run on the UI thread, so there you can change the 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(); }

For this to run, you need the WAKE_LOCK permission.

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

2. Download from Service

The big question here is: how do I update my activity from a service?. In the next example we are going to use two classes you may not be aware of: ResultReceiver and IntentServiceResultReceiver is the one that will allow us to update our thread from a service; IntentService is a subclass of Service which spawns a thread to do background work from there (you should know that a Service runs actually in the same thread of your app; when you extends Service, you must manually spawn new threads to run CPU blocking operations).

Download service can look like this:

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(url.openStream()); 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); } }

Add the service to your manifest:

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

And the activity will look like this:

// 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);

Here is were ResultReceiver comes to play:

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(); } } } }

2.1 Use Groundy library

Groundy is a library a friend and I wrote time ago. It basically helps you run pieces of code in a background service, and it is based on the ResultReceiver concept shown above. This is how thewhole code would look like...

The activity where you are showing the dialog...

public class MainActivity extends Activity { private ProgressDialog mProgressDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() { public void onClick(View view) { String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim(); Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build(); Groundy.create(DownloadExample.this, DownloadTask.class) .receiver(mReceiver) .params(extras) .queue(); mProgressDialog = new ProgressDialog(MainActivity.this); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setCancelable(false); mProgressDialog.show(); } }); } private ResultReceiver mReceiver = new ResultReceiver(new Handler()) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); switch (resultCode) { case Groundy.STATUS_PROGRESS: mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS)); break; case Groundy.STATUS_FINISHED: Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG); mProgressDialog.dismiss(); break; case Groundy.STATUS_ERROR: Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show(); mProgressDialog.dismiss(); break; } } }; }

GroundyTask implementation used by Groundy to download the file and show the progress:

public class DownloadTask extends GroundyTask { public static final String PARAM_URL = "com.groundy.sample.param.url"; @Override protected boolean doInBackground() { try { String url = getParameters().getString(PARAM_URL); File dest = new File(getContext().getFilesDir(), new File(url).getName()); DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this)); return true; } catch (Exception pokemon) { return false; } } }

And just add this to the manifest:

<service android:name="com.codeslap.groundy.GroundyService"/>

It couldn't be easier I think. Just grab the latest jar from Github and you are ready to go. Keep in mind that Groundy's main purpose is to make calls to external REST apis in a background service and post results to the UI with easily. If you are doing something like that in your app, it could be really useful.

3. Use DownloadManager class (GingerBread and newer only)

This method is awesome, you do not have to worry about downloading the file manually, handle threads, streams, etc. GingerBread brought a new feature: DownloadManager which allows you to download files easily and delegate the hard work to the system.

First, let's see a utility method:

/** * @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; } }

Method's name explains it all. Once you are sure DownloadManager is available, you can do something like this:

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);

Download progress will be showing in the notification bar.

Final thoughts

First and second methods are just the tip of the iceberg. There are lots of things you have to keep in mind if you want your app to be robust. Here is a brief list:

  • You must check whether user has an internet connection available
  • Make sure you have the right permissions (INTERNET and WRITE_EXTERNAL_STORAGE); also ACCESS_NETWORK_STATE if you want to check internet availability.
  • Make sure the directory were you are going to download files exist and has write permissions.
  • If download is too big you may want to implement a way to resume the download if previous attempts failed.
  • Users will be grateful if you allow them to interrupt the download.

Unless you want to have full control over the download process, I highly recommend using DownloadManager which already handles most of the items listed above.

本文转载自:http://blog.csdn.net/caiwenfeng_for_23/article/details/26495421

蜀山下的鱼
粉丝 9
博文 405
码字总数 0
作品 0
广州
高级程序员
私信 提问
开源平台引领机器翻译

令人惊讶的速度,机器语言翻译现在正在高速发展到各个平台上,其中开源软件扮演着重要的角色。十年前,未来学家如Ray Kurzweil 就预测我们使用的设备在翻译语言上将变得更快更高效,现在正在...

小卒过河
2011/10/18
1K
5
Android Studio 1.0 官网下载链接

Android Studio 1.0 是作为稳定版本发布的,现已提供下载:Android 开发者网站 但官网下载页面http://developer.android.com/sdk/index.html 国内很多时候打不开,下载链接贴在迅雷上倒是可以...

vane_
2014/12/09
0
0
Android开发学习总结(一)——搭建最新版本的Android开发环境

最近由于工作中要负责开发一款Android的App,之前都是做JavaWeb的开发,Android开发虽然有所了解,但是一直没有搭建开发环 境去学习,Android的更新速度比较快了,Android1.0是2008年发布的,...

wensongyu
2015/04/16
0
0
6 款超清爽安卓应用,带你告别臃肿

前言 受不了动不动就几十上百M的应用安装包,启动龟速还赠送广告大礼包,体验很不友好。 下面这 6 款超清爽的安卓应用/工具分享给大家,一起体验下安卓应用该有的样子。 推荐 谷歌拼音输入法...

己立
2018/05/27
0
0
Ubuntu10.10下配置Android开发环境 及 2.2,2.3 SDK下载

这篇日志是在http://hi.baidu.com/long_ri/blog/item/d9411a1007aa7a0f213f2e8e.html 的基础上根据我的实际情况修改而来。当然,大家还可以参照官方的《system Requirements》,还有个问题就...

长平狐
2012/11/01
549
0

没有更多内容

加载失败,请刷新页面

加载更多

一个简单易用的Linux文本编辑器:nano的安装与使用

许多状况下咱们都必要编纂云主机里的文本情节,而现时用的比力多的文本编纂器是vim,这个估量许多人都以为很难用,这边伏笔VPS引荐一个简略易用的文本编纂器nano,比vim简略许多,很轻易上手...

shzwork
21分钟前
1
0
go recover

异常、错误常见语言处理 一般语言都有其错误处理方式,就以鄙人熟悉的php来距离吧。 PHP有多个级别的错误处理方式,以防止程序在还未正确执行完毕时,就造成了程序的提前结束。 try/catch/fi...

o0无忧亦无怖
39分钟前
0
0
玩转混合云+边缘计算,且看ZStack Mini!

文章导读:2019年4月16日,ZStack新品和合作伙伴战略发布会上,面向集团客户和边缘场景需求,ZStack重磅推出ZStack Mini超融合一体机(以下简称:ZStack Mini)和ZStack多云管理平台(以下简...

ZStack社区版
41分钟前
1
0
springboot 整合redis

springboot整合redis官方是有文档的: 英文看不懂可以翻译,代码应该看得懂, 这个是自动注入的。当然也可以xml注入,手动配置。 整合步骤: pom文件: <!-- spring boot web --> ...

jason_kiss
45分钟前
2
0
手机耗电问题,大部分是没有正确使用这个“锁”

当安卓设备闲置时,设备很快会进入休眠状态,以达到省电和减少CPU占用的目的。但有些应用在手机灭屏甚至系统休眠时,依然频繁占用CPU处理事件或唤醒屏幕提示用户消息,这类行为会导致手机耗电...

安卓绿色联盟
46分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部