开发者社区> 问答> 正文

Android下载在ProgressDialog显示下载进度

我正在尝试写一个简单的应用,然后应用可以进行更新。为了做成这个,我需要一个简单的功能,就是可以进行下载一个文件,同时在一个ProgressDialog显示出当前的下载进度。我知道如何做ProgressDialog,但是我不知道在同一个地方怎么既下载一个文件又显示当前的进度。

展开
收起
蛮大人123 2016-02-15 09:50:48 4382 0
1 条回答
写回答
取消 提交回答
  • 我说我不帅他们就打我,还说我虚伪

    有很多下载文件的方法,接下来我将贴出最常用的一些方法;究竟哪一种对你的应用来说最实用取决于你。使用AsyncTask,在一个对话框中显示下载进度这个方法可以让你进行后台处理的同时更新UI(在这种情况下,我们将更新一个进度条)
    这是实例代码:

    // 声明对话框是你activity的成员字段
    ProgressDialog mProgressDialog;
    
    // 举例说明在onCreate中的方法
    mProgressDialog = new ProgressDialog(YourActivity.this);
    mProgressDialog.setMessage("A message");
    mProgressDialog.setIndeterminate(false);
    mProgressDialog.setMax(100);
    mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    
    DownloadFile downloadFile = new DownloadFile();
    downloadFile.execute("the url to the file you want to download");

    AsyncTask像这样:

    // 通常,AsyncTask子类在activity类中进行声明
    // 这样,你可以很容易在这里修改UI线程
    private class DownloadFile extends AsyncTask<String, Integer, String> {
        @Override
        protected String doInBackground(String... sUrl) {
            try {
                URL url = new URL(sUrl[0]);
                URLConnection connection = url.openConnection();
                connection.connect();
                //这将是有用的,这样你可以显示一个典型的0-100%的进度条
                int fileLength = connection.getContentLength();
    
                // 下载文件
                InputStream input = new BufferedInputStream(url.openStream());
                OutputStream output = new FileOutputStream("/sdcard/file_name.extension");
    
                byte data[] = new byte[1024];
                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    total += count;
                    publishProgress((int) (total * 100 / fileLength));
                    output.write(data, 0, count);
                }
    
                output.flush();
                output.close();
                input.close();
            } catch (Exception e) {
            }
            return null;
        }

    上边的方法(doInBackground)一直在一个后台线程中进行。你不需要做任何UI的任务。另一方面,onProgressUpdate和onPreExecute在UI线程上运行,因此你可以改变进度条

     @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mProgressDialog.show();
        }
    
        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            mProgressDialog.setProgress(progress[0]);
        }
    }

    一旦文件已经下载完,如果你想要执行一些代码(例如mProgressDialog.dismiss()),你也可能想要重写onPostExecute方法。

    2.从服务器下载

    这个大的问题是:我如何从服务器上更新我的activity?在下个示例中,我们将使用两个你可能没有太注意过的类:ResultReceiver和IntentService. ResultReceiver允许我们从服务器上更新我们的线程的类,IntentService 是Service的一个子类,从那,它可以产生一个线程来处理后台任务(你应该知道,你的应用的Service在同样的进程运行;当你继承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 {
                URL url= new URL(urlToDownload);
               URLConnection connection= url.openConnection();
                connection.connect();
               // 这将是有用的,这样你可以显示一个典型的0-100%的进度条
               int fileLength= connection.getContentLength();
               // 下载文件
               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;
                   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);
       }
    }

    向你的manifest中加service

    Activity将像这样
    // 像第一个例子那样初始化进度条
    //这是你怎么启动下载器
    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");
                mProgressDialog.setProgress(progress);
                if (progress == 100) {
                    mProgressDialog.dismiss();
                }
            }
        }
    }

    3.使用DownloadManager 类(GingerBread ,而且仅仅是最新的)
    这个方法是可怕的,你不用担心手动下载文件,处理线程,数据流,等等。GingerBread有一个新的特点,DownloadManager可以让你很容易的下载文件,然后将辛苦的工作给系统做。

    /**
     * @ param上下文用来检查设备的版本和DownloadManager信息
     * @如果下载管理器可以用,则返回true
     */
    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;
       }
    }

    方法的名字直接就解释了。一旦你确定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");
    // 如果为了让它运行,你必须用android3.2编译你的应用程序
    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");
    // 获得下载服务和队列文件
    DownloadManager manager= (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    manager.enqueue(request);

    下载进度条将在通知栏显示
    第一个和第二个方法仅仅是冰山一角。如果你想要你的app是健壮的,这有很多事情需要你记住。这是一个简短的列表:
    你必须检查用户是否有可用的网络链接。
    确定你有权限((INTERNET and
    WRITE_EXTERNAL_STORAGE);如果你想要检查网络是否可用也可以用ACCESS_NETWORK_STATE
    确保你要下载的文件的目录存在,有读写权限
    如果下载包太大,之前的下载失败了,你可能需要实现一种方法来恢复下载
    如果你允许用户中断下载,他们会很感激你。
    除非你已经完全控制了下载过程,否则我强烈建议你使用DownloadManager ,它已经实现了上边列出的大部分功能。

    2019-07-17 18:42:57
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
58同城Android客户端Walle框架演进与实践之路 立即下载
Android组件化实现 立即下载
蚂蚁聚宝Android秒级编译——Freeline 立即下载