progressBar说明

在某些操作的进度中的可视指示器,为用户呈现操作的进度,还它有一个次要的进度条,用来显示中间进度,如在流媒体播放的缓冲区的进度。

一个进度条也可不确定其进度。在不确定模式下,进度条显示循环动画。这样的模式经常使用于应用程序使用任务的长度是未知的。

XML重要属性

android:progressBarStyle:默认进度条样式

android:progressBarStyleHorizontal:水平样式

progressBar重要方法

getMax():返回这个进度条的范围的上限

getProgress():返回进度

getSecondaryProgress():返回次要进度

incrementProgressBy(int diff):指定添加的进度

isIndeterminate():指示进度条是否在不确定模式下

setIndeterminate(boolean indeterminate):设置不确定模式下

setVisibility(int v):设置该进度条是否可视

progressBar重要事件

onSizeChanged(int w, int h, int oldw, int oldh):当进度值改变时引发此事件

项目实现步骤分析

1.给进度调设置最大值

2.不管哪一个线程下载都要记录进度条当前位置,并设置值

3.给textview设置显示当前下载值

4.创建暂时文件把曾经下载好的位置记录起来

5.当线程下载完后删除暂时保存进度条位置的文件

主要代码:

加入权限

<uses-permission android:name="android.permission.INTERNET"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

布局文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android_download"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.android_download.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>

StreamTools工具

android线程下载的工具一样http://blog.csdn.net/zhaoyazhi2129/article/details/27189465

Activity主要代码

package com.example.android_download;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL; import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast; import com.example.util.StreamTools; public class MainActivity extends Activity {
private int threadNum = 3;// 线程开启的数量
private int threadRunning = 3;// 正在执行的线程
private TextView tv_pb;
private EditText et_url;
private ProgressBar pb_download;
private int currentPb;//当前值 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findView(); File sdDir = Environment.getExternalStorageDirectory();
File pdFile = new File(sdDir, "pb.txt");
InputStream is = null;
try {
// 推断文件是否存在
if (pdFile.exists()) {
is = new FileInputStream(pdFile);
} } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (is != null) {
String value = StreamTools.streamToStr(is);
//拆分
String arr[] = value.split(";"); pb_download.setMax(Integer.valueOf(arr[0]));// 最大值
currentPb = Integer.valueOf(arr[1]);// 当前值
pb_download.setProgress(currentPb);
tv_pb.setText("当前的进度是:"+arr[2]);
}
} /**
*
*/
public void findView() {
tv_pb = (TextView) findViewById(R.id.tv_pb);
et_url = (EditText) findViewById(R.id.et_url);
pb_download = (ProgressBar) findViewById(R.id.pb_download);
} // 下载文件(得到server端的文件大小 )
public void downLoadFile(View v) {
// 获取下载路径
final String spec = et_url.getText().toString();
if (TextUtils.isEmpty(spec)) {
Toast.makeText(this, "下载地址不能为空", 0).show();
} else {
new Thread() {
@Override
public void run() {
// 訪问网络地址
try {
// 依据下载的地址构建url对象
URL url = new URL(spec);
// 通过URL对象的openConnection()方法打开连接,返回一个连接对象
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
// 设置请求头
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(5000);
httpURLConnection.setReadTimeout(5000); // 推断是否响应成功
if (httpURLConnection.getResponseCode() == 200) {
/**
* 第一步:得到server下载文件的大小,然后在本地设置一个暂时文件和server端文件大小一致
*/
// 获取文件长度
int fileLength = httpURLConnection
.getContentLength();
//给进度条设置最大值
pb_download.setMax(fileLength);
//推断SD卡是否可用
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
// 外部存储设备的路径
File sdFile = Environment
.getExternalStorageDirectory();
//获取文件名
String fileName = spec.substring(spec.lastIndexOf("/")+1);
// 随机訪问文件的读取与写入RandomAccessFile(file, mode)
RandomAccessFile accessFile = new RandomAccessFile(
new File(sdFile, fileName), "rwd");
// 设置暂时文件与server文件大小一致
accessFile.setLength(fileLength);
// 关闭暂时文件
accessFile.close(); /**
* 第二步:计算出每一个线程下载的大小(開始位置,结束位置)
*/
// 计算出每一个线程下载的大小
int threadSize = fileLength / threadNum;
// for循环,计算出每一个线程的開始和结束位置
for (int threadId = 1; threadId <= 3; threadId++) {
int startIndex = (threadId - 1) * threadSize;// 開始位置
int endIndex = threadId * threadSize - 1;// 结束位置
if (threadId == threadNum) {// 最后一个 线程
endIndex = fileLength - 1;
} System.out.println("当前线程--" + threadId
+ "-----開始位置" + startIndex + "----结束位置"
+ endIndex + "-----线程大小" + threadSize);
/**
* 第三步:每创建好一次就要开启线程下载
*/
new DownLoadThread(threadId, startIndex,
endIndex, spec,fileName).start(); }
}else {
runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "SD卡不存在", 1).show();
}
});
}
} else {
runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "server端返回错误", 1).show();
}
});
} } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start(); }
} /**
* 每创建好一次就要开启线程下载
*
* @author zhaoyazhi
*
*/
class DownLoadThread extends Thread {
// 成员变量
private int threadId;
private int startIndex;
private int endIndex;
private String path;
private String fileName; File sdFile = Environment.getExternalStorageDirectory(); /**
*
* @param threadId
* 线程的序号
* @param startIndex
* 线程下载開始位置
* @param endIndex
* 线程下载结束位置
* @param path
* 线程下载保存文件的路径
*/
public DownLoadThread(int threadId, int startIndex, int endIndex,
String path,String fileName) {
super();
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.path = path;
this.fileName = fileName;
} @Override
public void run() {
// 能够通过每一个线程去下载文件
try {
/**
* 第四步:从本地文件上读取已经下载文件的開始位置
*/
File recordFile = new File(sdFile, threadId + ".txt");
if (recordFile.exists()) {
// 读取文件
InputStream is = new FileInputStream(recordFile);
// 利用工具类转换
String value = StreamTools.streamToStr(is);
// 获取记录的位置
int recordIndex = Integer.parseInt(value);
// 把记录的位置付给開始位置
startIndex = recordIndex;
}
// 通过path对象构造URL 对象
URL url = new URL(path);
// 通过URL对象openConnection
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
// 设置请求头
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(5000);
// 设置下载文件的開始位置和结束位置
httpURLConnection.setRequestProperty("Range", "bytes="
+ startIndex + "-" + endIndex);
// 获取状态码
int code = httpURLConnection.getResponseCode();
// System.out.println(code);
// 推断是否成功 仅仅要设置"Range"头,返回的状态码就是206
if (code == 206) {
// 获取每一个线程返回的流对象
InputStream is = httpURLConnection.getInputStream();
// 创建随机訪问的对象
RandomAccessFile accessFile = new RandomAccessFile(
new File(sdFile, fileName), "rwd");
// 指定開始位置
accessFile.seek(startIndex);
// 定义读取的长度
int len = 0;
// 定义缓冲区
byte buffer[] = new byte[1024*1024];
int total = 0;
// 循环读取
while ((len = is.read(buffer)) != -1) {
System.out.println("当前线程--" + threadId
+ "-----当前下载的位置是" + (startIndex + total));
// 保存每一个线程的下载位置
RandomAccessFile threadFile = new RandomAccessFile(
new File(sdFile, threadId + ".txt"), "rwd");
// 记录每次下载位置
threadFile.writeBytes((startIndex + total) + "");
threadFile.close();
accessFile.write(buffer, 0, len);
total += len;// 已经下载大小 /**
* 当程序有多个线程訪问一个变量。能够用synchronized解决
*/
synchronized (MainActivity.this) {
//进度条当前进度
currentPb += len;
pb_download.setProgress(currentPb);
final String percent= currentPb*100l/pb_download.getMax()+"%";
runOnUiThread(new Runnable() { @Override
public void run() {
//计算百分比操作 tv_pb.setText("当前的进度是:"+percent);
}
});
//创建保存当前 进度和百分比
RandomAccessFile pbFile = new RandomAccessFile(
new File(sdFile, "pb.txt"), "rwd");
pbFile.writeBytes(pb_download.getMax()+";"+currentPb+";"+percent);
pbFile.close();
} }
accessFile.close();
is.close(); runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "当前线程" + threadId + "---完成下载", 1).show();
}
});
/**
* 第五步:当你的n个线程都完成下载 的时候我才进行删除记录下载位置的缓存文件
*/
deleteRecordFile();
} else {
runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "server端返回错误", 1).show();
}
});
}
// 设置你下载文件
} catch (Exception e) {
e.printStackTrace();
} } } /**
* synchronized避免线程同步 下载完删除存储文件下载位置的暂时文件
*/
public synchronized void deleteRecordFile() {
// 外部存储设备的路径
File sdFile = Environment.getExternalStorageDirectory();
// 线程下载完就减去
threadRunning--;
// 当没有正在执行的线程
if (threadRunning == 0) {
for (int i = 1; i <= 3; i++) {
File recordFile = (new File(sdFile, i + ".txt"));
if (recordFile.exists()) {
recordFile.delete();
}
File pbFile = (new File(sdFile, "pb.txt"));
if (pbFile.exists()) {
pbFile.delete();
}
} }
} }

补充知识点

不用在给进度条设置值的时候考虑同步。由于android定义progressBar的时候已经 设置了同步

2.当程序有多个线程訪问一个变量,能够用synchronized解决

synchronized (MainActivity.this) {
//进度条当前进度
currentPb += len;
pb_download.setProgress(currentPb); runOnUiThread(new Runnable() { @Override
public void run() {
tv_pb.setText("当前的进度是:"+currentPb*100/pb_download.getMax()+"%");
}
});

执行结果

1.当文件下载时,进度条显示和当前进度显示

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb3lhemhpMjEyOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

2.当又一次载入时继续上次下载

3.当文件进行下载时,暂时存储下载文件位置的pb.txt被创建

4.当线程完成下载后,在主线程Toast完成下载

5.当下在完毕后进度条走满,当前进度为100%

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb3lhemhpMjEyOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

6.下载完后,暂时文件销毁

源码下载地址:http://download.csdn.net/detail/zhaoyazhi2129/7406731

转发请标明出处:http://blog.csdn.net/zhaoyazhi2129/article/details/27192169

赵雅智_android多线程下载带进度条的更多相关文章

  1. 赵雅智_Android的getResources()资源引用

    今天做一个Android的刮刮乐项目.里面用到非常多的地方用到了getResources. <span style="font-size:12px;"> // 获得图片 ...

  2. 赵雅智_Android编码规范

    凝视 导入mycodetemplates.xml统一凝视样式 须要加凝视的地方 类凝视(必加) 方法凝视(必加) 块凝视主要是数据结构和算法的描写叙述(必加) 类成员变量和常量凝视(选择性加入) 单行 ...

  3. 赵雅智_Android案例_刮刮乐

    实现效果 主要代码 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns ...

  4. 赵雅智_android获取本机运营商,手机号部分能获取

    手机号码不是全部的都能获取.仅仅是有一部分能够拿到. 这个是因为移动运营商没有把手机号码的数据写入到sim卡中.SIM卡仅仅有唯一的编号.供网络与设备 识别那就是IMSI号码,手机的信号也能够说是通过 ...

  5. Java POI 3.17导出EXCEL并下载(带进度条提示)

    导出数据 共4590条 只需要 5 秒左右,性能还算可以 我们再来测试一下 50000 条的性能...

  6. 赵雅智:android教学大纲

    带下划线为详细内容链接地址.点击后可跳转.希望给大家尽一些微薄之力.眼下还在整理中 教学章节 教学内容 学时安排 备注 1 Android高速入门 2 Android模拟器与常见命令 3 Androi ...

  7. android:异步任务asyncTask介绍及异步任务下载图片(带进度条)

    为什么要用异步任务? 在android中仅仅有在主线程才干对ui进行更新操作.而其他线程不能直接对ui进行操作 android本身是一个多线程的操作系统,我们不能把全部的操作都放在主线程中操作 .比方 ...

  8. Android -- 自定义带进度条的按钮

    1. 实现了一个带进度条的按钮,完成后显示提示信息,并设置按钮为不可再次被点击

  9. atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7

    atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7 1. 实现原理 1 2. 大的文件上传原理::使用applet 1 3. 新的bp 2 1. 性能提升---分割小文件上传 ...

随机推荐

  1. 防火墙 0x80070422

    1.无法打开操作中心-安全服务,解决方法:控制面板->管理工具->服务,找到Security Center 服务,双击打开,查看启动类型是否设置成禁用,是的话更改成自动或者延迟启动,之后就 ...

  2. 使用开源库 MBProgressHUD 等待指示器

    source https://github.com/jdg/MBProgressHUD MBProgressHUD is an iOS drop-in class that displays a tr ...

  3. TextView设置最多显示指定个字符,超过部分显示...(省略号)

    今天在公司遇到一个需求:TextView设置最多显示8个字符,超过部分显示...(省略号),网上找了很多资料,有人说分别设置TextView的android:signature="true& ...

  4. Lombok的安装及入门

    lombok 的官方网址:http://projectlombok.org/ lombok 其实到这里我就介绍完了,开个玩笑,其实官网上有 lombok 三分四十九秒的视频讲解,里面讲的也很清楚了,而 ...

  5. Mongodb安全认证及Java调用

    Mongodb安全认证在单实例和副本集两种情况下不太一样,单实例相对简单,只要在启动时加上 --auth参数即可,但副本集则需要keyfile. 一.单实例 1.启动服务(先不要加auth参数) 2. ...

  6. 什么是'脑分裂(split brain)'?

    这个词明显有点恐怖.设想一下,如果某时刻连接两个控制器之间的通路出现了问题,而不是其中某个控制器死机,此时两个控制器其实都是工作正常的,但是两者都检测不到对方的存在,所以两者都尝试接管所有总线,这时候 ...

  7. Android之AlarmManager

    Android平台中,Alarm Manager Service控制着闹钟和唤醒功能.和其他系统服务一样,提供了一个辅助管理类-AlarmManager,我们只需要使用AlarmManager即可调用 ...

  8. statickeyword

    static词义:静态的,可以用于修饰变量和方法,static方法块可以优先于构造函数运行. 被static修饰的变量,叫静态变量,静态变量在内存中仅仅有一份拷贝 public static Stri ...

  9. Package.json小结

        生成package.json 定位到想放置package.json的目录,运行npm init,根据提示就可以生成package.json文件,其中test command可以为空. 安装mo ...

  10. [Node.js]25. Level 5. Route params

    Create a route that responds to a GET request '/quotes/<name>', then use the param from the UR ...