android多线程下载详解
- 博客分类:
- android
本文将介绍在android平台下如何实现多线程下载,大家都知道,android平台使用java做为开发语言,所以java中支持的多线程下载方式在android平台下都支持,其中主要有两种方式可以实现多线程下载。
一种方式是使用很多个线程分别下载文件的不同部分,最后把所有下载完的文件合并成一个文件。另一种方式是使用java为我们提供的RandomAccessFile类实现多线程的下载。
从性能上分析,第二种方式的存取速度会慢一些,但开发起来较为容易,不需要进行合并文件等操作。本文将使用第二种方式来实现多线程下载,最终效果如下图所示:
第一步,我们先写一个线程类,来完成对指定区域的数据进行下载,如下所示:
package com.ideasandroid.demo; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.URL; import java.net.URLConnection; import android.util.Log; /** * Copyright (C) 2010 ideasandroid * 演示android多线程下载 * 欢迎访问http://www.ideasandroid.com * 让程序开发不再那么神秘 * * 单个下载线程 */ public class FileDownloadThread extends Thread{ private static final int BUFFER_SIZE=1024; private URL url; private File file; private int startPosition; private int endPosition; private int curPosition; //用于标识当前线程是否下载完成 private boolean finished=false; private int downloadSize=0; public FileDownloadThread(URL url,File file,int startPosition,int endPosition){ this.url=url; this.file=file; this.startPosition=startPosition; this.curPosition=startPosition; this.endPosition=endPosition; } @Override public void run() { BufferedInputStream bis = null; RandomAccessFile fos = null; byte[] buf = new byte[BUFFER_SIZE]; URLConnection con = null; try { con = url.openConnection(); con.setAllowUserInteraction(true); //设置当前线程下载的起点,终点 con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition); //使用java中的RandomAccessFile 对文件进行随机读写操作 fos = new RandomAccessFile(file, "rw"); //设置开始写文件的位置 fos.seek(startPosition); bis = new BufferedInputStream(con.getInputStream()); //开始循环以流的形式读写文件 while (curPosition < endPosition) { int len = bis.read(buf, 0, BUFFER_SIZE); if (len == -1) { break; } fos.write(buf, 0, len); curPosition = curPosition + len; if (curPosition > endPosition) { downloadSize+=len - (curPosition - endPosition) + 1; } else { downloadSize+=len; } } //下载完成设为true this.finished = true; bis.close(); fos.close(); } catch (IOException e) { Log.d(getName() +" Error:", e.getMessage()); } } public boolean isFinished(){ return finished; } public int getDownloadSize() { return downloadSize; } }
接下来就是使用图形界面来获取需要下载的内容,并实时更新下载进度条,代码如下所示:
package com.ideasandroid.demo; import java.io.File; import java.net.URL; import java.net.URLConnection; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; /** * Copyright (C) 2010 ideasandroid * 演示android多线程下载 * 欢迎访问http://www.ideasandroid.com * 让程序开发不再那么神秘 */ public class FileDownloadDemo extends Activity { private EditText downloadUrl; private EditText downloadFileName; private EditText downloadThreadNum; private Button downloadBt; private ProgressBar downloadProgressBar; private TextView progressMessage; private int downloadedSize = 0; private int fileSize = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); downloadUrl = (EditText) findViewById(R.id.downloadUrl); downloadFileName = (EditText) findViewById(R.id.downloadFileName); downloadThreadNum = (EditText) findViewById(R.id.downloadThreadNum); progressMessage = (TextView) findViewById(R.id.progressMessage); downloadBt = (Button) findViewById(R.id.downloadBt); downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar); downloadProgressBar.setVisibility(View.VISIBLE); downloadProgressBar.setMax(100); downloadProgressBar.setProgress(0); downloadBt.setOnClickListener(new OnClickListener() { public void onClick(View v) { download(); } }); } private void download() { // 获取SD卡目录 String dowloadDir = Environment.getExternalStorageDirectory() + "/ideasdownload/"; File file = new File(dowloadDir); //创建下载目录 if (!file.exists()) { file.mkdirs(); } //读取下载线程数,如果为空,则单线程下载 int downloadTN = Integer.valueOf("".equals(downloadThreadNum.getText() .toString()) ? "1" : downloadThreadNum.getText().toString()); //如果下载文件名为空则获取Url尾为文件名 int fileNameStart = downloadUrl.getText().toString().lastIndexOf("/"); String fileName = "".equals(downloadFileName.getText().toString()) ? downloadUrl .getText().toString().substring(fileNameStart) : downloadFileName.getText().toString(); //开始下载前把下载按钮设置为不可用 downloadBt.setClickable(false); //进度条设为0 downloadProgressBar.setProgress(0); //启动文件下载线程 new downloadTask(downloadUrl.getText().toString(), Integer .valueOf(downloadTN), dowloadDir + fileName).start(); } Handler handler = new Handler() { @Override public void handleMessage(Message msg) { //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息 int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue(); if (progress == 100) { downloadBt.setClickable(true); progressMessage.setText("下载完成!"); } else { progressMessage.setText("当前进度:" + progress + "%"); } downloadProgressBar.setProgress(progress); } }; /** * @author ideasandroid * 主下载线程 */ public class downloadTask extends Thread { private int blockSize, downloadSizeMore; private int threadNum = 5; String urlStr, threadNo, fileName; public downloadTask(String urlStr, int threadNum, String fileName) { this.urlStr = urlStr; this.threadNum = threadNum; this.fileName = fileName; } @Override public void run() { FileDownloadThread[] fds = new FileDownloadThread[threadNum]; try { URL url = new URL(urlStr); URLConnection conn = url.openConnection(); //获取下载文件的总大小 fileSize = conn.getContentLength(); //计算每个线程要下载的数据量 blockSize = fileSize / threadNum; // 解决整除后百分比计算误差 downloadSizeMore = (fileSize % threadNum); File file = new File(fileName); for (int i = 0; i < threadNum; i++) { //启动线程,分别下载自己需要下载的部分 FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1); fdt.setName("Thread" + i); fdt.start(); fds[i] = fdt; } boolean finished = false; while (!finished) { // 先把整除的余数搞定 downloadedSize = downloadSizeMore; finished = true; for (int i = 0; i < fds.length; i++) { downloadedSize += fds[i].getDownloadSize(); if (!fds[i].isFinished()) { finished = false; } } //通知handler去更新视图组件 handler.sendEmptyMessage(0); //休息1秒后再读取下载进度 sleep(1000); } } catch (Exception e) { } } } }
发表评论
-
[Android]倒影效果的ImagView by sodino
2012-04-18 17:36 864效果图如下: pac ... -
使用PorterDuffXfermode实现遮罩层
2012-04-18 17:09 1143最近在开发一个小游戏中,用到一个显示当前进度的进度条,如下图所 ... -
对Canvas和Matrix的理解的简介与内容
2012-04-18 16:09 995不了解Matrix的同学看这里: 弄明白ma ... -
ImageView.setScaleType(ImageView.ScaleType)详解
2012-04-18 14:33 12001、这里我们重点懂得ImageView的属性android:s ... -
android:shape的使用
2012-04-17 17:47 520Android中常常使用shape来定义控件的一些显示属 ... -
ListView滑动分页
2012-04-12 16:36 0SCROLL_STATE_FLING是指手指快速拖动后,手指离 ... -
android xml解析 XmlPullParser的使用
2012-02-07 14:26 892android xml 的解析. 1.普通型 &l ... -
Android杂谈---读取XML资源
2012-02-07 13:51 919获取XML文件的基本思路 ... -
Android SAX API: XmlResourceParser及其扩展应用
2012-02-07 12:02 7public Vector<Map<Objec ... -
android网络传输的传送对象
2012-01-12 17:03 767此方法将对象写入对象流,然后转换成string,故适用于htt ... -
教你如何开关Android的APN网络
2011-09-15 11:12 685由于Android对于APN的网络API没有公开,不过我们 ... -
android 使用CMWAP接入点访问互联网
2011-09-15 10:46 899Android是个公认的好系统 ... -
android 创建兼容CMWAP连接的应用程序
2011-09-15 10:16 1052在Android开发中,经常会用到连接网络的操作,比如下 ... -
ListView分页加载数据
2011-09-08 14:11 954对于ListView分页加载数据,是正常情况下是非常有必要。一 ... -
ListView 实现像Android Market那样 分页加载 滚动加载
2011-09-07 14:57 1048ListView 实现像Android Market那样 分页 ... -
android 一个TabHost的例子
2011-09-07 11:30 1259package com.eric; import and ... -
android播放gif动画控件(例子)
2011-09-07 10:34 17381.测试程序 package com.test; ... -
ListView动态加载数据
2011-09-06 18:05 11711. 引言: 为了提高ListV ... -
ListView 异步加载图片源码
2011-09-06 17:51 11851.AsyncListImage.java packa ... -
Android 动态加载布局
2011-09-06 10:49 1304由于前段时间项目需 ...
相关推荐
Android多线程处理 详解,比较详细的分析了Android的多线程机理
12_Android 多线程AsyncTask详解
一些在Android上巧妙使用多线程的方法与经验,希望对大家有所帮助
Android多线程详解.pdf
android客户端多线程下载,断点续传,多线程下载,网络编程详解代码 网络搜索《Android 4.0 网络编程详解代码》中的 第5章:Android中的网络数据下载及JSON的操作 中代码不全,少了个终于的activity,现自己跑通后上传以...
主要为大家详细介绍了Android多线程下载示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
在上一篇博文《Android多线程下载示例》中,我们讲解了如何实现Android的多线程下载功能,通过将整个文件分成多个数据块,开启多个线程,让每个线程分别下载一个相应的数据块来实现多线程下载的功能。多线程下载中,...
Android Asynctask 先小试牛刀,了解一下各个方法执行过程,关注博客http://himici.com/
主要对handler 、message机制进行了详解,如果想了解更多android相关知识,可以去我博客看看
下面是一段大家都比较熟悉的代码: 代码如下:Handler ...上述代码中的handler并没有调用线程myThread的start()方法,而是直接调用了run()方法,这也就意味着实际上并没有创建一个新的线程,只是在当前线程中调用run()
主要介绍了Android多线程,结合实例形式较为详细的分析了Android多线程的概念、使用方法与相关注意事项,需要的朋友可以参考下
本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信。 一、android当中的多线程 在Android当中,当一个应用程序的组件启动的时候,并且没有其他的应用程序组件在运行时,...
我们会用到OKHttp3来做网络请求,使用RxJava来实现线程的切换,并且开启Java8来启用Lambda表达式,毕竟RxJava实现线程切换非常方便,而且数据流的形式也非常舒服,同时Lambda和RxJava配合食用味道更佳 打开我们的app ...
本文主要介绍了Android中多线程下载的几个步骤以及实现功能的具体代码,具有很好的参考价值,需要的朋友一起来看下吧
Android 多线程的实例详解 Java多线程方式 1. 继承Thread线程,实现run方法 2. 实现Runnable接口 JAVA单继承性,当我们想将一个已经继承了其他类的子类放到Thread...Android多线程方式 主要集中在UI线程和其他线
handler.post(r)其实这样并不会新起线程,只是执行的runnable里的run()方法,却没有执行start()方法,所以runnable走的还是UI线程。 1.如果像这样,是可以操作ui,但是run还是走在主线程,见打印出来的Log线程名字是...
Android–多线程之Handler 前言 Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不 允许Activity新启动的线程访问该Activity里的UI组件,...