Android开发(7) 文件下载

概述

我们在开发中经常需要从服务器下载文件,下载的内容可能有交换的信息,缓存的图片,程序更新包等。我们使用URLConnection来实现下载。

先看几行代码:

           String urlDownload = "";
           urlDownload = "http://www.baidu.com/img/baidu_sylogo1.gif";

            URL url = new URL(urlDownload );    
            // 打开连接    
            URLConnection con = url.openConnection(); 
       
            // 输入流    
            InputStream is = con.getInputStream();  

如上面的代码所示,指定一个下载的目标链接,我们上面指定了一个图片地址。然后构建一个URL对象,调用该对象的openConnection方法来建立一个数据通路(连接)。代码的最后一行使用 con.getInputStream,拿到一个输入流对象,通过这个流对象我们就可以读取到这个文件的内容了。下面要做的,就是读取这个流,将流写入我们的本地文件。

不过在这之前,我们还要说下这个方法:

  //获得文件的长度
            int contentLength = con.getContentLength();
            System.out.println("长度 :"+contentLength);

获得文件长度的方法

ContentLength是不很熟啊。它是http协议里描述头(head)部分的描述属性之一。实际这里是发送了一个http请求,分析了返回(response)里数据内容。

我们常常会把文件下载到手机的存储卡里,所以还会用到获得存储卡路径的方法:

获得存储卡路径,构成 保存文件的目标路径

            String dirName = "";
            dirName = Environment.getExternalStorageDirectory()+"/MyDownload/";
            File f = new File(dirName);
            if(!f.exists())
            {
                f.mkdir();
            }

Environment.getExternalStorageDirectory() 方法会返回一个字符串,指示了存储卡的路径。我们拼接字符串出一个准备存放下载文件的文件夹。并先判断文件夹是是否存在,如果不存在,则新建一个文件夹。

做完了上面的准备后,基本就能实现下载了。

完整代码

下载前的准备工作:

//要下载的文件路径
String urlDownload = "";
//urlDownload =  "http://192.168.3.39/text.txt%22;
urlDownload =     "http://www.baidu.com/img/baidu_sylogo1.gif%22;
// 获得存储卡路径,构成 保存文件的目标路径
String dirName = "";
dirName = Environment.getExternalStorageDirectory()+"/MyDownload/";
File f = new File(dirName);
if(!f.exists())
{
    f.mkdir();
}

下载的操作

//准备拼接新的文件名(保存在存储卡后的文件名)
      String newFilename = _urlStr.substring(_urlStr.lastIndexOf("/")+1);
      newFilename = _dirName + newFilename;
    File file = new File(newFilename);
    //如果目标文件已经存在,则删除。产生覆盖旧文件的效果
    if(file.exists())
    {
        file.delete();
    }
    try {
           // 构造URL    
            URL url = new URL(_urlStr);    
            // 打开连接    
            URLConnection con = url.openConnection(); 
            //获得文件的长度
            int contentLength = con.getContentLength();
            System.out.println("长度 :"+contentLength);
            // 输入流    
            InputStream is = con.getInputStream();   
          
            // 1K的数据缓冲    
            byte[] bs = new byte[1024];    
            // 读取到的数据长度    
            int len;    
           // 输出的文件流    
            OutputStream os = new FileOutputStream(newFilename);    
            // 开始读取    
            while ((len = is.read(bs)) != -1) {    
              os.write(bs, 0, len);    
            }   
            // 完毕,关闭所有链接    
            os.close();   
            is.close(); 
        
    } catch (Exception e) {
            e.printStackTrace();
    }

完整的代码下载

进阶篇 - 增加进度条提示下载进度

我们先来看下进度条

<ProgressBar 
  android:id="@+id/ProgressBar01" 
  style="?android:attr/progressBarStyleHorizontal" 
  android:layout_height="wrap_content" 
  android:visibility="visible" 
  android:max="100"
  android:progress="1"
  android:layout_width="200dp"/>

上面展示了一个水平的进度条。max属性指定了最大值,progress指示当前的进度位置。style指定了一个现实风格。

“观察者”模式

不得不说的一个是设计模式里的“观察者”模式。观察者模式提供了一个“让一个观察者去观察一个对象,当观察的目标发生变化时,通知给 订阅了观察结果的对象 ”。这句话纯属于个人理解。

它表达了几个对象:
1.订阅了“观察结果的对象”,该对象会收到“观察者”的通知。
2.观察者对象,一个紧盯这 目标对象 的对象。它负责将 观察的目标 的变化 通知给 “订阅者”
3.被观察的目标,会发生变化的目标对象,它的变化及时的都被观察者所知。

在我们的下载时我们的几个对象是

1.进度条,是订阅者,它接受观察者对象的消息,来显示自己的进度条位置。

2.观察者,是一个handler对象。该对象适合在线程间传递消息。我们就用它传递消息的特点,并且该对象属于android平台核心框架,和主界面的消息循环有联系。

3.被观察的目标就是下载的过程了。这个过程中下载文件的进度。

我们分别实现它

private Handler myHandler = new Handler(){
 public void handleMessage(android.os.Message msg) {
  //获得进度,该进度由实际的操作进行通知。这里负责对通知进行处理
  int progress = msg.arg1;
  //设置进度条的当前位置
  _ProgressBar01.setProgress(progress);
  if(progress == 100)
  {
   Toast.makeText(getApplicationContext(), "下载成功", 0).show();
   
  }
  
 };
};

我们构建一个myHandler 对象,并重载了它的handleMessage方法,该方法会捕获(收到)所有发送给myHandler 的消息。我们接收消息,并根据消息携带的信息arg1作为当前的进度表示。

下面我们将这个myHandler 传递给下载的线程

new FileDownloader(urlDownload,dirName,myHandler).start();

如上面这行代码所示,FileDownloader对象是个下载器对象,它负责下载文件,同时他和观察者myHandler关联。有了消息,它就告诉这个观察者。观察者收到消息,通知给订阅了消息的对象(本文为进度条)。

下面看下如何进行下载进程的:

// 构造URL    
   URL url = new URL(_urlStr);    
   // 打开连接    
   URLConnection con = url.openConnection(); 
   //获得文件的长度
   int contentLength = con.getContentLength();
   System.out.println("长度 :"+contentLength);
   // 输入流    
   InputStream is = con.getInputStream();   
 
   int hasRead = 0;//已经读取了多少
   int progress = 0;
   
   // 1K的数据缓冲    
   byte[] bs = new byte[128];    
   // 读取到的数据长度    
   int len;    
  // 输出的文件流    
   OutputStream os = new FileOutputStream(newFilename);    
   // 开始读取    
   while ((len = is.read(bs)) != -1) {    
     os.write(bs, 0, len); 
     
     //记录完成了的多少
     hasRead +=len;
     progress = (int)((double)hasRead/(double)contentLength * 100);//完成的百分比
     //发送通知
     Message msg = _myHandler.obtainMessage();
     msg.arg1 = progress;
     msg.sendToTarget();
     
     Thread.sleep(500);//故意延迟,不然进度条跑的太快看不清楚
   }   
   // 完毕,关闭所有链接    
   os.close();   
   is.close();

我们记录我们当前从服务器读了多少字节,又知道总共需要下载多少字节。计算后,得到一个完成了多少的百分比。将这个百分比通知给 观察者。

完整的代码下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容