java – 使用Android下载文件,并在ProgressDialog中显示进度

weixin_38096704 2019-09-12 12:43:22
我正在尝试编写一个更新的简单应用程序.为此,我需要一个简单的函数,可以下载文件并在ProgressDialog中显示当前进度.我知道如何进行ProgressDialog,但我不知道如何显示当前进度以及如何首先下载文件.
...全文
98 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
weixin_38102396 2019-09-12
  • 打赏
  • 举报
回复
有很多方法可以下载文件.以下我将发布最常见的方式;您可以自行决定哪种方法更适合您的应用. 1.使用AsyncTask并在对话框中显示下载进度 此方法将允许您执行一些后台进程并同时更新UI(在这种情况下,我们将更新进度条). 这是一个示例代码: // 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); //cancel the task } }); 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线程上运行,因此您可以更改进度条: @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(); } 要运行此操作,您需要WAKE_LOCK权限. <uses-permission android:name="android.permission.WAKE_LOCK" /> 2.从服务下载 这里最大的问题是:如何从服务更新我的活动?在下一个示例中,我们将使用您可能不知道的两个类:ResultReceiver和IntentService. ResultReceiver是允许我们从服务更新线程的那个; IntentService是Service的一个子类,它产生一个线程来从那里进行后台工作(你应该知道一个服务实际上在你的app的同一个线程中运行;当你扩展Service时,你必须手动生成新的线程来运行CPU阻塞操作) . 下载服务可能如下所示: 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 { //create url and connect 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()); String path = "/sdcard/BarcodeScanner-debug.apk" ; OutputStream output = new FileOutputStream(path); 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); } // close streams output.flush(); output.close(); input.close(); } catch (IOException e) { e.printStackTrace(); } Bundle resultData = new Bundle(); resultData.putInt("progress" ,100); receiver.send(UPDATE_PROGRESS, resultData); } } 将服务添加到清单: <service android:name=".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来玩: 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"); //get the progress dialog.setProgress(progress); if (progress == 100) { dialog.dismiss(); } } } } 2.1使用Groundy库 Groundy是一个基本上可以帮助您在后台服务中运行代码片段的库,它基于上面显示的ResultReceiver概念.此库已弃用.这就是整个代码的样子: 您正在显示对话框的活动… 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; } } }; } Groundy使用GroundyTask实现下载文件并显示进度: 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; } } } 然后将其添加到清单中: <service android:name="com.codeslap.groundy.GroundyService"/> 我想这可不容易.只需抓住最新的罐子from Github就可以了.请记住,Groundy的主要目的是在后台服务中调用外部REST apis,并轻松地将结果发布到UI.如果你在你的应用程序中做了类似的事情,它可能真的很有用. 2.2使用https://github.com/koush/ion 3.使用DownloadManager类(仅限GingerBread和更新版本) 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) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { return true; } return false; } 方法的名称解释了这一切.一旦确定DownloadManager可用,您可以执行以下操作: 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); 下载进度将显示在通知栏中. 最后的想法 第一种和第二种方法只是冰山一角.如果您希望自己的应用程序功能强大,那么您需要记住很多事情.这是一个简短的清单: >您必须检查用户是否有可用的互联网连接>确保您拥有正确的权限(INTERNET和WRITE_EXTERNAL_STORAGE);如果您想查看互联网可用性,还可以访问ACCESS_NETWORK_STATE.>确保目录是否要下载存在的文件并具有写入权限.>如果下载太大,您可能希望实现一种方法,以便在先前的尝试失败时恢复下载.>如果您允许用户中断下载,用户将不胜感激. 除非您需要详细控制下载过程,否则请考虑使用DownloadManager(3),因为它已经处理了上面列出的大多数项目. 但也要考虑您的需求可能会发生变化.例如,DownloadManager does no response caching.它将盲目地多次下载相同的大文件.事后没有简单的方法来解决它.如果你从一个基本的HttpURLConnection(1,2)开始,那么你只需要添加一个HttpResponseCache.因此,学习基本标准工具的初步努力可能是一项很好的投资. This class was deprecated in API level 26. ProgressDialog is a modal dialog, which prevents the user from interacting with the app. Instead of using this class, you should use a progress indicator like ProgressBar, which can be embedded in your app’s UI. Alternatively, you can use a notification to inform the user of the task’s progress. For more details 07004

435

社区成员

发帖
与我相关
我的任务
社区描述
其他技术讨论专区
其他 技术论坛(原bbs)
社区管理员
  • 其他技术讨论专区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧