yiranwujixian
2012-09-21 01:55
采纳率: 100%
浏览 10.9k
已采纳

用android下载一个文件,在ProgressDialog显示下载进度

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

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • liangchichexin 2012-09-21 02:38
    已采纳

    有很多下载文件的方法,接下来我将贴出最常用的一些方法;究竟哪一种对你的应用来说最实用取决于你。

    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

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

    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 ,它已经实现了上边列出的大部分功能。

    点赞 打赏 评论
  • niangzhi 2012-09-21 05:15

    如果你要从网络上下载东西,不要忘记给你的manifest文件添加许可

    <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>
    
    点赞 打赏 评论
  • franzhong 2012-09-21 08:49
    public class EX04_17 extends Activity 
    { 
      private TextView mTextView01;
      private Button mButton01; 
      private ProgressBar mProgressBar01; 
      public int intCounter=0; 
      /* 自定义Handler讯息代码,用以作为识别事件处理 */ 
      protected static final int GUI_STOP_NOTIFIER = 0x108; 
      protected static final int GUI_THREADING_NOTIFIER = 0x109;
      /** Called when the activity is first created. */
      @Override
      public void onCreate(Bundle savedInstanceState)
    { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    mButton01 = (Button)findViewById(R.id.myButton1);
    mTextView01 = (TextView)findViewById(R.id.myTextView1); 
    /* 设定ProgressBar widget对象 */ 
    mProgressBar01 = (ProgressBar)findViewById(R.id.myProgressBar1); 
    /* 调用setIndeterminate方法指派indeterminate模式为false */
    mProgressBar01.setIndeterminate(false); 
    /* 当按下按钮后,开始线程工作 */ 
    mButton01.setOnClickListener(new Button.OnClickListener()
    {
    
    @Override
    public void onClick(View v) 
    { 
      // TODO Auto-generated method stub 
      /* 按下按钮让ProgressBar显示 */ 
      mTextView01.setText(R.string.str_progress_start);
      /* 将隐藏的ProgressBar显示出来 */ 
      mProgressBar01.setVisibility(View.VISIBLE);
      /* 指定Progress为最多100 */ 
      mProgressBar01.setMax(100); 
      /* 初始Progress为0 */
      mProgressBar01.setProgress(0); 
      /* 起始一个线程 */ 
      new Thread(new Runnable() 
      { 
        public void run()
        { 
          /* 预设0至9,共执行10次的循环叙述 */ 
          for (int i=0;i<10;i++) 
          { 
            try 
            {
              /* 成员变量,用以识别加载进度 */ 
              intCounter = (i+1)*20; 
              /* 每执行一次循环,即暂停1秒 */ 
              Thread.sleep(1000); 
              /* 当Thread执行5秒后显示执行结束 */ 
              if(i==4)
              {
                /* 以Message对象,传递参数给Handler */ 
                Message m = new Message(); 
                /* 以what属性指定User自定义 */ 
                m.what = EX04_17.GUI_STOP_NOTIFIER;
                EX04_17.this.myMessageHandler.sendMessage(m); 
                break; 
                } 
              else 
              {
                Message m = new Message(); 
                m.what = EX04_17.GUI_THREADING_NOTIFIER;
                EX04_17.this.myMessageHandler.sendMessage(m); 
                }
              } 
            catch(Exception e)
            { 
              e.printStackTrace(); 
              }
            } 
          }
        }
      ).start(); 
      } 
    }); 
    } 
    
    
    /* Handler建构之后,会聆听传来的讯息代码 */ 
      Handler myMessageHandler = new Handler() 
      { 
        // @Override
        public void handleMessage(Message msg)
        {
          switch (msg.what) 
          { 
          /* 当取得识别为 离开线程时所取得的讯息 */ 
          case EX04_17.GUI_STOP_NOTIFIER:
            /* 显示执行终了 */ 
            mTextView01.setText(R.string.str_progress_done); 
            /* 设定ProgressBar Widget为隐藏 */ 
            mProgressBar01.setVisibility(View.GONE); 
            Thread.currentThread().interrupt();
            break;
            /* 当取得识别为 持续在线程当中时所取得的讯息 */
            case EX04_17.GUI_THREADING_NOTIFIER:
              if(!Thread.currentThread().isInterrupted()) 
              {
                mProgressBar01.setProgress(intCounter); 
                /* 将显示进度显示于TextView当中 */ 
                mTextView01.setText ( getResources().getText(R.string.str_progress_start)+
                    "("+Integer.toString(intCounter)+"%)\n"+
                    "Progress:"+
                    Integer.toString(mProgressBar01.getProgress())+
                    "\n"+"Indeterminate:"+
                    Boolean.toString(mProgressBar01.isIndeterminate()) ); 
                } 
              break;
              } 
          super.handleMessage(msg);
          } 
        }; 
        }
    

    在线程的try里进行文件下载操作~

    点赞 打赏 评论

相关推荐 更多相似问题