android_36_多线程断点续传

来源:互联网 发布:java中获取当前时间 编辑:程序博客网 时间:2024/06/06 02:59

效果图:






原理图:


清单:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.sg31.multiplethreaddownload"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="8"        android:targetSdkVersion="21" />    // 注意权限     <uses-permission android:name="android.permission.INTERNET"/>    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>        <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name=".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>




布局:

<LinearLayout 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="com.sg31.multiplethreaddownload.MainActivity" android:orientation="vertical"    >    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="开始下载"         android:onClick="downloadBtnClicked"        /><ProgressBar     android:id="@+id/progressBar"    android:layout_width="match_parent"    android:layout_height="wrap_content"    style="@android:style/Widget.ProgressBar.Horizontal"    /><TextView     android:id="@+id/tv"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    /></LinearLayout>


代码:


package com.sg31.multiplethreaddownload;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.ProgressBar;import android.widget.TextView;public class MainActivity extends ActionBarActivity {static int ThreadCount = 3;static int finishedThread = 0;int currentProgress;String fileName = "NEXT_TO_YOU.mp3";// 确定下载地址String path = "http://1od8vj43og.bkt.clouddn.com/" + fileName;private ProgressBar progressBar;TextView tv;Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {// 把变量改成long,在long下运算tv.setText((long) progressBar.getProgress() * 100/ progressBar.getMax() + "%");}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 控件progressBar = (ProgressBar) findViewById(R.id.progressBar);tv = (TextView) findViewById(R.id.tv);}@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;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();if (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);}public void downloadBtnClicked(View v) {Thread t = new Thread() {@Overridepublic void run() {// 发送get请求,请求这个地址的资源的长度try {URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);if (conn.getResponseCode() == 200) {// 拿到所请求资源文件的长度int length = conn.getContentLength();// 设置进度条的最大值就是原文件的总长度progressBar.setMax(length);File file = new File(Environment.getExternalStorageDirectory(),fileName);// 生成临时文件,rwd表示实时写入底层设备RandomAccessFile raf = new RandomAccessFile(file, "rwd");// 设置临时文件的大小raf.setLength(length);raf.close();// 计算出每个线程应该下载多少字节int size = length / ThreadCount;for (int i = 0; i < ThreadCount; i++) {// 计算线程下载的开始位置和结束位置int startIndex = i * size;int endIndex = (i + 1) * size - 1;// 如果是最后一个线程,那么结束位置写死if (i == ThreadCount - 1) {endIndex = length - 1;}// System.out.println("线程" + i + "的下载区间是:" +// startIndex + "---" + endIndex);new DownLoadThread(startIndex, endIndex, i).start();}}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();}// 专门用来下载的类class DownLoadThread extends Thread {int startIndex;int endIndex;int threadId;public DownLoadThread(int startIndex, int endIndex, int threadId) {super();this.startIndex = startIndex;this.endIndex = endIndex;this.threadId = threadId;}@Overridepublic void run() {// 再次发送http请求,下载原文件try {File progressFile = new File(Environment.getExternalStorageDirectory(), threadId+ ".txt");// 判断进度临时文件是否存在if (progressFile.exists()) {FileInputStream fis = new FileInputStream(progressFile);BufferedReader br = new BufferedReader(new InputStreamReader(fis));// 从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置int lastProgress = Integer.parseInt(br.readLine());startIndex += lastProgress;// 把上次下载的进度显示至进度条currentProgress += lastProgress;progressBar.setProgress(currentProgress);// 发送消息,让主线程刷新文本进度handler.sendEmptyMessage(1);fis.close();}System.out.println("线程" + threadId + "的下载区间是:" + startIndex+ "---" + endIndex);HttpURLConnection conn;URL url = new URL(path);conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);// 核心代码:设置本次http请求所请求的数据的区间conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);// 请求部分数据,相应码是206if (conn.getResponseCode() == 206) {// 流里此时只有1/3原文件的数据InputStream is = conn.getInputStream();byte[] b = new byte[1024];int len = 0;int total = 0;// 拿到临时文件的输出流File file = new File(Environment.getExternalStorageDirectory(), fileName);RandomAccessFile raf = new RandomAccessFile(file, "rwd");// 核心代码:把文件的写入位置移动至startIndexraf.seek(startIndex);while ((len = is.read(b)) != -1) {// 每次读取流里数据之后,同步把数据写入临时文件raf.write(b, 0, len);total += len;System.out.println("线程" + threadId + "下载了" + total);// 每次读取流里数据之后,把本次读取的数据的长度显示至进度条currentProgress += len;progressBar.setProgress(currentProgress);// 发送消息,让主线程刷新文本进度handler.sendEmptyMessage(1);// 生成一个专门用来记录下载进度的临时文件RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");// 每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中progressRaf.write((total + "").getBytes());progressRaf.close();}System.out.println("线程" + threadId+ "下载完毕-------------------sg31.com");raf.close();finishedThread++;synchronized (path) {if (finishedThread == ThreadCount) {for (int i = 0; i < ThreadCount; i++) {File f = new File(Environment.getExternalStorageDirectory(),i + ".txt");f.delete();}finishedThread = 0;}}}} catch (Exception e) {e.printStackTrace();}}}}


0 0
原创粉丝点击