Android开发(24)---安卓中实现多线程下载(带进度条和百分比)
来源:互联网 发布:镜面蛋糕走红网络 编辑:程序博客网 时间:2024/05/19 16:49
当我们学完java中多线程的下载后,可以将它移植到我们的安卓中来,下面是具体实现源码:
DownActivity.java
package com.example.downloads;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import com.example.downloads.utils.DownLoadThread;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.annotation.SuppressLint;import android.app.Activity;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;public class DownActivity extends Activity {// 声明控件// 路径与线程数量public EditText et_url, et_num;// 进度条public static ProgressBar pb_thread;// 显示进度的操作public TextView tv_pb;// 线程的数量public static int threadNum = 3;// 每个线程负责下载的大小public int blockSize;public static int threadCount;// 数量// 访问的pathpublic String path;public static boolean flag = true;// 记录进度条的值public static int pb_count = 0;public static Handler handler;public static final int TEXTVALUE = 1;public static int pb_num = 0;public static int size = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_down);et_url = (EditText) findViewById(R.id.et_path);et_num = (EditText) findViewById(R.id.et_threadNum);pb_thread = (ProgressBar) findViewById(R.id.pb_down);tv_pb = (TextView) findViewById(R.id.tv_pb);handler = new Handler() {@SuppressLint("HandlerLeak")@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case TEXTVALUE:System.out.println("-------" + DownActivity.pb_count+ "//////" + DownActivity.size);// 改变TEXTViewpb_num = (DownActivity.pb_count * 100) / DownActivity.size;tv_pb.setText("当前进度是+" + pb_num + "%");break;default:break;}}};}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}public void downLoad(View v) {DownActivity.flag = true;DownActivity.pb_count = 0;path = et_url.getText().toString();String threadNum_et = et_num.getText().toString();if (TextUtils.isEmpty(path) || TextUtils.isEmpty(threadNum_et)) {Toast.makeText(this, "不能为空", Toast.LENGTH_LONG).show();return;}Toast.makeText(this, "url:" + path + "--" + threadNum_et,Toast.LENGTH_LONG).show();// 转换成数字threadNum = Integer.valueOf(threadNum_et);new Thread(new Runnable() {@Overridepublic void run() {try {// 创建出URL对象URL url = new URL(path);// 创建出 HttpURLConnection对象HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();// 设置 发请求发送的方式httpURLConnection.setRequestMethod("GET");// 设置请求是否超时时间httpURLConnection.setConnectTimeout(5000);// 设置httpURLConnection.setRequestProperty("User-Agent"," Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)");// 是否响应成功if (httpURLConnection.getResponseCode() == 200) {// 获取文件的大小size = httpURLConnection.getContentLength();System.out.println("文件的大小" + size);// 设置进度条的最大值pb_thread.setMax(size);// 创建文件 //保存到SD卡上// 首先判断是否拥有sdcardif (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {// 获取sdCard文件目录对象File sdFile = Environment.getExternalStorageDirectory();// 创建文件对象File file = new File(sdFile, "youdao.exe");RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 设置文件的大小accessFile.setLength(size);// 每个线程下载的大小blockSize = size / threadNum;// 开三个线程 操作此文件for (int i = 1; i <= threadNum; i++) {// 1 2 3// 计算出每个线程开始的位置int startSize = (i - 1) * blockSize;// 结束位置int endSize = (i) * blockSize;// 当线程是最后一个线程的时候if (i == threadNum) {// 判断文件的大小是否大于计算出来的结束位置if (size > endSize) {// 结束位置 等于 文件的大小endSize = size;}}// 为每个线程创建一个随机的读取RandomAccessFile threadAccessFile = new RandomAccessFile(file, "rwd");new Thread(new DownLoadThread(i,threadAccessFile, startSize, endSize,path)).start();}}}} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}).start();}/** * 暂停操作 * * @param v */public void downPause(View v) {Toast.makeText(this, "暂停", Toast.LENGTH_LONG).show();this.flag = false;}}
DownLoadThread.java
package com.example.downloads.utils;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import com.example.downloads.DownActivity;import android.os.Environment;public class DownLoadThread implements Runnable {public RandomAccessFile accessFile; // 每个线程 都拥有一个accessFile的文件对象 线程1 线程2 线程3// 线程下载文件的起始位置public int startSize;public int endSize;// 文件下载的path路径public String path;public int threadId; // 线程的标识public DownLoadThread(int threadId, RandomAccessFile accessFile,int startSize, int endSize, String path) {this.threadId = threadId;this.accessFile = accessFile;this.startSize = startSize;this.endSize = endSize;this.path = path;}@Overridepublic void run() {// 执行run方法try {// 创建文件到SD卡上去// 首先判断是否拥有sdcardif (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {// 获取sdCard文件目录对象File sdFile = Environment.getExternalStorageDirectory();File threadFile = new File(sdFile, threadId + ".txt");if (threadFile.exists()) {// 读取该文件的内容// 创建文件的输入流对象FileInputStream fis = new FileInputStream(threadFile);// 采用工具类读取byte data[] = StreamTools.isToData(fis);// 转化成字符串String threadLen = new String(data);if ((threadLen != null) && (!"".equals(threadLen))) {startSize = Integer.valueOf(threadLen);// 解决 416bug的错误if (startSize > endSize) {startSize = endSize - 1;}}}// 创建文件// 创建URL对象URL url = new URL(path);// 创建HttpURLConnection对象HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();// 设置请求的头httpURLConnection.setRequestMethod("GET");// 设置请求是否超时时间httpURLConnection.setConnectTimeout(5000);// 设置httpURLConnection.setRequestProperty("User-Agent"," Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)");// 关键的设置httpURLConnection.setRequestProperty("Range", "bytes="+ startSize + "-" + endSize);// 输出当前线程System.out.println("当前线程" + threadId + " 下载开始位置:" + startSize+ " 下载结束位置:" + endSize);// 响应成功// 设置随机读取文件的 开始位置accessFile.seek(startSize);// 获取相应流对象InputStream is = httpURLConnection.getInputStream();// 创建输出流对象byte buffer[] = new byte[1024];int len = 0;int threadTotal = 0;// 每个线程下载后保存记录 /while ((len = is.read(buffer)) != -1) {accessFile.write(buffer, 0, len);threadTotal += len;// 记录你写入的长度 //xml文件//改变进度条:setProgressBar(len);// 通过文件记录文件下载的长度FileOutputStream fos = new FileOutputStream(threadFile);fos.write((threadTotal + "").getBytes());fos.flush();fos.close();//发送handler消息DownActivity.handler.sendEmptyMessage(DownActivity.TEXTVALUE);if(!DownActivity.flag){return;}}accessFile.close();is.close();System.out.println(threadId + "线程执行完毕");// 线程操作synchronized (DownActivity.class) {DownActivity.threadCount++;if (DownActivity.threadCount >= DownActivity.threadNum) {for (int i = 1; i <= DownActivity.threadNum; i++) {// 获取sdCard上的文件File deleteFile = new File(sdFile, i + ".txt");if (deleteFile.exists()) {// 文件删除deleteFile.delete();}}}}}} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public synchronized void setProgressBar(int len){DownActivity.pb_count+=len;DownActivity.pb_thread.setProgress(DownActivity.pb_count);}}
StreamTools.java
package com.example.downloads.utils;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;public class StreamTools {public static byte[] isToData(InputStream is) throws IOException{// 字节输出流ByteArrayOutputStream bops = new ByteArrayOutputStream();// 读取数据的缓存区byte buffer[] = new byte[1024];// 读取长度的记录int len = 0;// 循环读取while ((len = is.read(buffer)) != -1) {bops.write(buffer, 0, len);}// 把读取的内容转换成byte数组byte data[] = bops.toByteArray();bops.flush();bops.close();is.close();return data;}}
strings.xml
<?xml version="1.0" encoding="utf-8"?><resources> <string name="app_name">downloads</string> <string name="action_settings">Settings</string> <string name="tv_down">文件下载的地址</string> <string name="tv_threadNum">线程数量</string> <string name="tv_num">0%</string> <string name="btn_text">下载</string> <string name="btn_pause">暂停</string> <string name="et_path">http://172.22.64.8:8080/doudou/youdao.exe</string> <string name="et_threadNum">3</string></resources>
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".DownActivity" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:text="@string/tv_down" /> <EditText android:id="@+id/et_path" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_below="@+id/textView1" android:ems="10" android:inputType="none" android:text="@string/et_path" > <requestFocus /> </EditText> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/et_path" android:text="@string/tv_threadNum" /> <EditText android:id="@+id/et_threadNum" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/textView2" android:layout_alignRight="@+id/et_path" android:layout_below="@+id/textView2" android:ems="10" android:inputType="number" android:text="@string/et_threadNum" /> <ProgressBar android:id="@+id/pb_down" style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/et_threadNum" android:layout_alignRight="@+id/et_threadNum" android:layout_below="@+id/et_threadNum" android:layout_marginTop="14dp" /> <TextView android:id="@+id/tv_pb" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@+id/textView1" android:layout_below="@+id/pb_down" android:layout_marginTop="24dp" android:text="@string/tv_num" /> <Button android:id="@+id/btn_down" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/pb_down" android:layout_below="@+id/tv_pb" android:layout_marginTop="32dp" android:onClick="downLoad" android:text="@string/btn_text" /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/btn_down" android:layout_below="@+id/btn_down" android:layout_marginTop="16dp" android:onClick="downPause" android:text="@string/btn_pause" /></RelativeLayout>
效果如下:
最后要注意的是别忘了在项目清单文件中加入权限:
<!-- SDCard权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 访问网络的权限 --> <uses-permission android:name="android.permission.INTERNET" />
- Android开发(24)---安卓中实现多线程下载(带进度条和百分比)
- Android百分比下载进度条
- Android百分比下载进度条
- 多线程断点下载(开始下载,暂停下载,百分比进度条)
- 多线程断点下载(开始下载,暂停下载,百分比进度条)
- android,实现圆形循环进度条,不带百分比进度显示
- Android自定义View实现带百分比圆形进度条
- C#带进度条和百分比的窗体实现过程
- js实现进度条(不带百分比)
- android 带百分比的自定义进度条
- 多线程断点续传显示进度条和百分比
- 从tomcat上下载MP3 带百分比进度条
- 【Android】自定义控件实现带百分比显示进度条,可自定义颜色
- 安卓实训第七天---多线程下载实现(进度条)
- JS+AS实现真正页面加载图片进度条(带百分比)
- swfupload + commons-fileupload实现文件批量上传,带百分比进度条
- 在JSP页面上实现不带百分比进度条
- 在JSP页面上实现进度条(带百分比)
- 一款jQuery打造的滚动条在底部滑出信息提示层
- WSO2 ESB(3)
- linux操作系统简史
- 发现一个很好的JS 开源IDE工具Aptana
- 查找只出现一次的字符串
- Android开发(24)---安卓中实现多线程下载(带进度条和百分比)
- JAVA------sort-----------------排序
- building android/ubuntu-touch on 32bit machine
- flyweight
- 使Android应用的AlertDialog对话框中的按钮显示为ImageButton图标,并设置相应
- Listview中布局控件导致点击事件失效的原因分析
- WSO2 ESB(4)
- Trie树和Ternary Search树的学习总结
- 设计模式_迭代模式