ANDROID笔记:多线程断点下载

 

//mainActivity

package com.example.multthreaddownload;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.annotation.SuppressLint;
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;

import com.example.multthreaddownload.DownLoadThread.DownLoadState;
import com.example.multthreaddownload.util.Breakpoint;
import com.example.multthreaddownload.util.MyPoint;

/**
 * 主类 实现DownLoadState接口,用于控制下载线程的结束
 * 
 * @author Administrator
 * 
 */
public class MainActivity extends Activity implements DownLoadState {
    private ProgressBar bar = null;
    private EditText text;
    private TextView textView;
    private int filelength = 0;
    // 下载状态
    private boolean isRunning = false;
    // 下载路径
    private File father = Environment.getExternalStorageDirectory();
    private File file = new File(father, "file.mp3");
    // 断点集合类
    private Breakpoint breakpoint = null;
    // 开始/暂停
    private boolean isPause = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        bar = (ProgressBar) findViewById(R.id.progressBar1);
        text = (EditText) findViewById(R.id.url);
        final Button button = (Button) findViewById(R.id.button1);
        textView = (TextView) findViewById(R.id.textView1);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isRunning) {
                    isRunning = false;
                    isPause = true;
                    button.setText("开始");
                } else {// 开始/继续下载
                    isRunning = true;
                    // 测试数据
                    text.setText("http://172.16.12.82:8080/AIAIAPP/file.mp3");
                    if (isPause) {
                        conntineDown();
                    } else {
                        startDown();
                    }
                    isPause = false;
                    button.setText("暂停");
                }
            }
        });
    }

    /* 消息处理 */
    int len = 0;
    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 0x1) {
                len = len + Integer.valueOf(msg.obj.toString());
                bar.setProgress(len);
                textView.setText(len + "/" + filelength);
            } else if (msg.what == 0x2) {
                if (breakpoint == null) {// 单例模式
                    breakpoint = new Breakpoint(text.getText().toString(),
                            file.getAbsolutePath());
                }
                // 得到各个线程的断点
                MyPoint myPoint = (MyPoint) msg.obj;
                // 添加到断点集合类
                breakpoint.add(myPoint);
            }
        }
    };

    /**
     * 下载线程
     */
    private void startDown() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                int threadNumber = 1;// 设置线程个数
                URL url;
                try {
                    url = new URL(text.getText().toString());
                    HttpURLConnection http = (HttpURLConnection) url
                            .openConnection();
                    filelength = http.getContentLength();// 获取下载文件的长度
                    // 设置进度条的最大值
                    bar.setMax(filelength);
                    System.out.println("文件长度:" + filelength);
                    // 每个线程需要下载的大小
                    int length = filelength / threadNumber;
                    for (int i = 0; i < threadNumber - 1; i++) {
                        new DownLoadThread().startDownload(MainActivity.this,
                                i, text.getText().toString(), file, i * length,
                                (i + 1) * length, handler);
                    }
                    // 最后一个线程下载剩余的空间
                    new DownLoadThread().startDownload(MainActivity.this, 4,
                            text.getText().toString(), file, (threadNumber - 1)
                                    * length, filelength, handler);
                    System.out.println("设置完毕");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }).start();
    }

    /**
     * 继续下载
     */
    private void conntineDown() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.err.println("继续下载");
                System.err.println(breakpoint.get().size());
                // 根据断点集合类中集合的大小生成下载线程
                for (int i = 0; i < breakpoint.get().size(); i++) {
                    // 得到各个断点
                    MyPoint point = breakpoint.get().get(i);
                    // 下载开始点和结束点:point.startPos--->point.endPos
                    new DownLoadThread().startDownload(MainActivity.this, i,
                            breakpoint.url, new File(breakpoint.filePath),
                            point.startPos, point.endPos, handler);
                }
                // 清空断点记录
                breakpoint.get().clear();
            }
        }).start();
    }

    /**
     * 实现接口,当返回的isRunning为false时,所有下载线程停止
     */
    @Override
    public boolean handle() {
        return isRunning;
    }

}

//下载工具类DownLoadThread

package com.example.multthreaddownload;

import java.io.File;
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 android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;

import com.example.multthreaddownload.util.MyPoint;

/**
 * 下载线程
 * 
 * @author Administrator
 * 
 */
public class DownLoadThread {
    private String urlString;
    private File file = null;
    private int startPos;
    private int endPos;
    // 用于将信息传递给主类
    private Handler handler;
    private int id = 0;
    // 控制线程的结束
    DownLoadState state = null;

    public void startDownload(DownLoadState state, int id, String urlString,
            File file, int startPos, int endPos, Handler handler) {
        this.state = state;
        this.id = id;
        this.urlString = urlString;
        this.file = file;
        this.startPos = startPos;
        this.endPos = endPos;
        this.handler = handler;
        // 启动下载线程
        new Thread(new myRunnable()).start();
    }

    private class myRunnable implements Runnable {
        @SuppressLint("SdCardPath")
        @Override
        public void run() {
            // {
            // Message msg = new Message();
            // msg.obj = "线程启动";
            // handler.sendMessage(msg);
            // }
            try {
                // System.err.println(startPos + "--->" + endPos);
                URL url = new URL(urlString);
                // System.out.println("file.exists():" + file.exists());
                // System.out.println(file.getAbsolutePath());
                if (!file.exists()) {
                    file.createNewFile();
                }
                // System.out.println("file.exists():" + file.exists());
                HttpURLConnection http = (HttpURLConnection) url
                        .openConnection();
                // 请求时长
                http.setConnectTimeout(5 * 1000);
                http.setRequestMethod("GET");
                http.setRequestProperty("Range", "bytes=" + startPos + "-"
                        + endPos);// 设置获取实体数据的范围
                InputStream inStream = http.getInputStream();
                byte[] buffer = new byte[1024];
                int offset = 0;
                RandomAccessFile threadfile = new RandomAccessFile(file, "rwd");
                // 设置距离文件开头的指针偏移量(将文件读写指针移动至startPos位置)
                threadfile.seek(startPos);
                int len = 0;
                // state.handle()控制循环(控制线程停止)
                while (state.handle()
                        && (offset = inStream.read(buffer, 0, 1024)) != -1) {
                    threadfile.write(buffer, 0, offset);
                    len = len + offset;
                    {// 将下载进度传递给主类,控制进度条
                        Message msg = new Message();
                        msg.what = 0x1;
                        msg.obj = offset;
                        handler.sendMessage(msg);
                    }
                }
                // 当线程停止时,将断点信息船体给主类
                if (!state.handle()) {
                    // System.err.println(id + "--" + startPos + "--"
                    // + (startPos + len) + "--" + endPos);
                    // System.err.println(id + "pause");
                    {
                        MyPoint point = new MyPoint((startPos + len), endPos);
                        Message msg = new Message();
                        msg.what = 0x2;
                        msg.obj = point;
                        handler.sendMessage(msg);
                    }
                }
                threadfile.close();
                inStream.close();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            {
                Message msg = new Message();
                msg.obj = "线程下载完毕";
                handler.sendMessage(msg);
            }
        }
    }

    /**
     * 接口
     * 
     * @author Administrator
     * 
     */
    public interface DownLoadState {
        public boolean handle();
    }

}

//断点集合类

package com.example.multthreaddownload.util;

import java.util.ArrayList;
import java.util.List;



public class Breakpoint {
    public String url;
    public String filePath;

    public Breakpoint(String url, String filePath) {
        this.url = url;
        this.filePath = filePath;
    }

    private List<MyPoint> points = new ArrayList<MyPoint>();

    public void add(MyPoint point) {
        points.add(point);
    }

    public List<MyPoint> get() {
        return points;
    }

}

//断点类

package com.example.multthreaddownload.util;

public class MyPoint {

    public int startPos;
    public int endPos;

    public MyPoint(int startPos, int endPos) {
        this.startPos = startPos;
        this.endPos = endPos;
    }

}

界面XML文件

<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=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/url"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="156dp"
        android:text="下载" />

    <EditText
        android:id="@+id/url"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="33dp"
        android:ems="10"
        android:singleLine="true" >

        <requestFocus />
    </EditText>

    <ProgressBar
        android:id="@+id/progressBar1"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/url"
        android:layout_below="@+id/url"
        android:layout_marginTop="60dp" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/progressBar1"
        android:layout_below="@+id/progressBar1"
        android:layout_marginTop="20dp"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

//需要下列权限(有wifi权限是因为在真机上用wifi调试了)

    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!-- 在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.READ_EXTERNAL_STORAGE" />

 

 

 

posted @ 2013-11-25 09:15  skyko  阅读(418)  评论(0编辑  收藏  举报