Download a file with Android, and showing the progress in a ProgressDialog
我正在尝试编写一个更新后的简单应用程序。为此,我需要一个简单的函数,它可以下载一个文件并显示
有很多方法可以下载文件。接下来我将发布最常见的方法;由您决定哪种方法更适合您的应用程序。
1。使用此方法将允许您执行一些后台进程并同时更新UI(在本例中,我们将更新进度条)。
这是一个示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 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 } }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | // 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; } |
上面的方法(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | @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(); } |
要运行此程序,您需要唤醒锁定权限。
1 | <uses-permission android:name="android.permission.WAKE_LOCK" /> |
2。从服务下载
这里的大问题是:如何从服务更新我的活动?.在下一个示例中,我们将使用两个您可能不知道的类:
下载服务可以如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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); } } |
将服务添加到清单:
1 | <service android:name=".DownloadService"/> |
活动将是这样的:
1 2 3 4 5 6 7 8 | // 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); |
这是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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是一个基本上帮助您在后台服务中运行代码片段的库,它基于上面所示的
显示对话框的活动…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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用来下载文件并显示进度的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } } } |
只需将此添加到清单:
10我想这不容易。只需从Github中获取最新的罐子,就可以开始了。记住,groundy的主要目的是在后台服务中调用外部RESTAPI,并轻松地将结果发布到UI。如果你在你的应用程序中做类似的事情,它可能真的很有用。
2.2使用https://github.com/koush/ion三。使用姜饼带来了一个新功能,
首先,我们来看一个实用方法:
1 2 3 4 5 6 7 8 9 10 11 | /** * @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; } |
方法的名称解释了这一切。一旦您确定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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连接
- 确保您拥有正确的权限(
INTERNET 和WRITE_EXTERNAL_STORAGE ;如果您想检查Internet可用性,还应确保ACCESS_NETWORK_STATE 。 - 确保您要下载的目录存在并且具有写权限。
- 如果下载太大,您可能希望实现一种方法,以便在以前的尝试失败时恢复下载。
- 如果您允许用户中断下载,用户将不胜感激。
除非您需要对下载过程进行详细控制,否则考虑使用
但也要考虑到你的需求可能会改变。例如,
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 Link
如果要从Internet下载内容,请不要忘记向清单文件添加权限!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.helloandroid" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission> <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> </application> </manifest> |
是的,上面的代码可以工作。但是如果你在EDOCX1的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | private void updateProgressBar(){ Runnable runnable = new updateProgress(); background = new Thread(runnable); background.start(); } public class updateProgress implements Runnable { public void run() { while(Thread.currentThread()==background) //while (!Thread.currentThread().isInterrupted()) { try { Thread.sleep(1000); Message msg = new Message(); progress = getProgressPercentage(); handler.sendMessage(msg); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { } } } private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { progress.setProgress(msg.what); } }; |
当您的活动不可见时,不要忘记销毁线程。
1 2 3 4 5 6 | private void destroyRunningThreads() { if (background != null) { background.interrupt(); background=null; } } |
我建议你使用我的项目Netroid,它是基于截击。我添加了一些功能,比如多事件回调、文件下载管理。这可能会有所帮助。
我已经修改了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | public static class DownloadTask extends AsyncTask<String, Integer, String> { private ProgressDialog mPDialog; private Context mContext; private PowerManager.WakeLock mWakeLock; private File mTargetFile; //Constructor parameters : // @context (current Activity) // @targetFile (File object to write,it will be overwritten if exist) // @dialogMessage (message of the ProgresDialog) public DownloadTask(Context context,File targetFile,String dialogMessage) { this.mContext = context; this.mTargetFile = targetFile; mPDialog = new ProgressDialog(context); mPDialog.setMessage(dialogMessage); mPDialog.setIndeterminate(true); mPDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mPDialog.setCancelable(true); // reference to instance to use inside listener final DownloadTask me = this; mPDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { me.cancel(true); } }); Log.i("DownloadTask","Constructor done"); } @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(); } Log.i("DownloadTask","Response" + connection.getResponseCode()); // 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(mTargetFile,false); byte data[] = new byte[4096]; long total = 0; int count; while ((count = input.read(data)) != -1) { // allow canceling with back button if (isCancelled()) { Log.i("DownloadTask","Cancelled"); 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; } @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) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName()); mWakeLock.acquire(); mPDialog.show(); } @Override protected void onProgressUpdate(Integer... progress) { super.onProgressUpdate(progress); // if we get here, length is known, now set indeterminate to false mPDialog.setIndeterminate(false); mPDialog.setMax(100); mPDialog.setProgress(progress[0]); } @Override protected void onPostExecute(String result) { Log.i("DownloadTask","Work Done! PostExecute"); mWakeLock.release(); mPDialog.dismiss(); if (result != null) Toast.makeText(mContext,"Download error:"+result, Toast.LENGTH_LONG).show(); else Toast.makeText(mContext,"File Downloaded", Toast.LENGTH_SHORT).show(); } } |
我发现这个博客帖子很有帮助,它使用loopj下载文件,它只有一个简单的功能,将有助于一些新的Android家伙。
不要忘记将"/sdcard…"替换为新文件("/mnt/sdcard/……"),否则您将得到一个filenotfoundexception
当我开始学习Android开发的时候,我已经了解到
在许多应用程序中,我所看到的最好的一面是,它们自定义了这个进度对话框的属性,以使进度对话框比股票版本具有更好的外观和感觉。很好地保持用户参与一些动画,如青蛙,大象或可爱的猫/小狗。任何带有"进行中"对话框的动画都会吸引用户,他们不想等待太久。
使用android查询库,确实很酷,你可以把它改为使用
1 2 3 4 5 6 7 8 | File target = new File(new File(Environment.getExternalStorageDirectory(),"ApplicationName"),"tmp.pdf"); new AQuery(this).progress(R.id.progress_view).download(_competition.qualificationScoreCardsPdf(), target, new AjaxCallback<File>() { public void callback(String url, File file, AjaxStatus status) { if (file != null) { // do something with file } } }); |
我个人的建议是在执行之前使用进度对话框并建立,或者在
我正在为我现在使用的其他解决方案添加另一个答案,因为Android查询太大,无法维护以保持健康。所以我转到了https://github.com/amitshekhariitbhu/fast-android-networking。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | AndroidNetworking.download(url,dirPath,fileName).build() .setDownloadProgressListener(new DownloadProgressListener() { public void onProgress(long bytesDownloaded, long totalBytes) { bar.setMax((int) totalBytes); bar.setProgress((int) bytesDownloaded); } }).startDownload(new DownloadListener() { public void onDownloadComplete() { ... } public void onError(ANError error) { ... } }); |
权限
1 2 3 | <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
使用httpurl连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import android.app.Activity; import android.app.Dialog; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class DownloadFileUseHttpURLConnection extends Activity { ProgressBar pb; Dialog dialog; int downloadedSize = 0; int totalSize = 0; TextView cur_val; String dwnload_file_path = "http://coderzheaven.com/sample_folder/sample_file.png"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button b = (Button) findViewById(R.id.b1); b.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showProgress(dwnload_file_path); new Thread(new Runnable() { public void run() { downloadFile(); } }).start(); } }); } void downloadFile(){ try { URL url = new URL(dwnload_file_path); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("GET"); urlConnection.setDoOutput(true); //connect urlConnection.connect(); //set the path where we want to save the file File SDCardRoot = Environment.getExternalStorageDirectory(); //create a new file, to save the downloaded file File file = new File(SDCardRoot,"downloaded_file.png"); FileOutputStream fileOutput = new FileOutputStream(file); //Stream used for reading the data from the internet InputStream inputStream = urlConnection.getInputStream(); //this is the total size of the file which we are downloading totalSize = urlConnection.getContentLength(); runOnUiThread(new Runnable() { public void run() { pb.setMax(totalSize); } }); //create a buffer... byte[] buffer = new byte[1024]; int bufferLength = 0; while ( (bufferLength = inputStream.read(buffer)) > 0 ) { fileOutput.write(buffer, 0, bufferLength); downloadedSize += bufferLength; // update the progressbar // runOnUiThread(new Runnable() { public void run() { pb.setProgress(downloadedSize); float per = ((float)downloadedSize/totalSize) * 100; cur_val.setText("Downloaded" + downloadedSize + "KB /" + totalSize +"KB (" + (int)per +"%)" ); } }); } //close the output stream when complete // fileOutput.close(); runOnUiThread(new Runnable() { public void run() { // pb.dismiss(); // if you want close it.. } }); } catch (final MalformedURLException e) { showError("Error : MalformedURLException" + e); e.printStackTrace(); } catch (final IOException e) { showError("Error : IOException" + e); e.printStackTrace(); } catch (final Exception e) { showError("Error : Please check your internet connection" + e); } } void showError(final String err){ runOnUiThread(new Runnable() { public void run() { Toast.makeText(DownloadFileDemo1.this, err, Toast.LENGTH_LONG).show(); } }); } void showProgress(String file_path){ dialog = new Dialog(DownloadFileDemo1.this); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.myprogressdialog); dialog.setTitle("Download Progress"); TextView text = (TextView) dialog.findViewById(R.id.tv1); text.setText("Downloading file from ..." + file_path); cur_val = (TextView) dialog.findViewById(R.id.cur_pg_tv); cur_val.setText("Starting download..."); dialog.show(); pb = (ProgressBar)dialog.findViewById(R.id.progress_bar); pb.setProgress(0); pb.setProgressDrawable( getResources().getDrawable(R.drawable.green_progress)); } } |