HttpURLConnection实现多线程网络下载

第一步:设计布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<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.example.multithread_download.MainActivity"
    android:orientation="vertical">

   <EditText
       android:id="@+id/id_url"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:hint="input download url"/>
    <EditText
        android:id="@+id/id_targetFile"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="input targetFile"/>
    <Button
        android:id="@+id/id_download"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="download"
        />
    <ProgressBar
        android:layout_marginTop="5dp"
        android:id="@+id/id_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:max="100"
        />
    <ImageView
        android:id="@+id/id_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@mipmap/ic_launcher"
        />

</LinearLayout>
运行效果如下:(以下载图片为例)

第二步:编写下载工具类(多线程下载)
public class DownUtil{
    //  定义下载路径
    private String path;
    //  要下载到的文件路径
    private String targetFile;
    private int threadNum;
    private DownThread[] threads;
    //  定义下载文件的总大小
    private int fileSize;

    public DownUtil(){

    }
    //  初始化下载所需数据
    public DownUtil(String path,String targetFile,int threadNum){
        this.path = path;
        this.targetFile = targetFile;
        this.threadNum = threadNum;
        threads = new DownThread[threadNum];
    }
    //  定义下载方法
    public void download(){
        try {
            URL url = new URL(path);
            //  获得到资源的链接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestProperty("Accept-Encoding","identity");
            conn.setConnectTimeout(5*10000);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Charset","UTF-8");
            conn.setRequestProperty("Accept-language","zh-CN");
            conn.setRequestProperty("Connection","Keep-Alive");
            //  获取要下载的文件的大小
            fileSize = conn.getContentLength();
            conn.disconnect();
            int currentPartSize = fileSize / threadNum + 1;
            //  创建一个文件读取流去读取targetFile所定义的文件,权限为读写
            RandomAccessFile file = new RandomAccessFile(targetFile,"rw");
            file.setLength(fileSize);
            file.close();
            for (int i = 0; i <threadNum ; i++) {
                int startPos = i*currentPartSize;
                RandomAccessFile currentPart = new RandomAccessFile(targetFile,"rw");
                currentPart.seek(startPos);
                threads[i] = new DownThread(startPos,currentPartSize,currentPart);
                threads[i].start();
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public double getConpleteRate(){
        int sumSize = 0;
        for(int i=0;i<threadNum;i++){
            sumSize += threads[i].length;
        }
        return sumSize * 1.0 / fileSize;
    }
    //  定义下载线程类
    private class DownThread extends Thread{
        private int startPos;
        private int currentPartSize;
        //  定义当前线程需要下载的文件块
        private RandomAccessFile currentPart;
        //  定义该线程需要下载的字节数
        public int length;

        public DownThread(int startPos,int currentPartSize,RandomAccessFile currentPart){
            this.startPos = startPos;
            this.currentPartSize = currentPartSize;
            this.currentPart = currentPart;
        }
        public void run(){
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5*1000);
                conn.setRequestMethod("GET");
                conn.setRequestProperty("Charset","utf-8");
                conn.setRequestProperty("Connection","Keep-Alive");
                InputStream is = conn.getInputStream();
                skipFully(is,this.startPos);
                byte buf[] = new byte[1024];
                int hasRead = 0;
                while(length < currentPartSize && (hasRead=is.read(buf))>0){
                    currentPart.write(buf,0,hasRead);
                    length +=hasRead;
                }
                currentPart.close();
                is.close();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //  定义一个为InputStream跳过bytes字节的方法
    //  因为输入流的skip方法有时候会读取不完整 所以创建一个读取方法循环读取知道读完为止
    public  static void skipFully(InputStream is,long bytes){
        long remainning = bytes;
        long len = 0;
        while(remainning > 0){
            try {
                len = is.skip(remainning);
                remainning -= len;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
第三步:在MainActivity中编写代码,实现下载功能并预览图片,因为下载任务是个耗时操作应放在线程中操作,对于UI的改变操作应该使用handler进行处理,使用定时器和ProgressBard对下载状态进行更新和显示:
public class MainActivity extends Activity {
    EditText url,target;
    Button btn_download;
    ProgressBar bar;
    ImageView show;
    DownUtil downUtill;
    //  定义进度条的状态值
    private int mDownStatus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        url = (EditText) findViewById(R.id.id_url);
        target = (EditText) findViewById(R.id.id_targetFile);
        btn_download = (Button) findViewById(R.id.id_download);
        bar = (ProgressBar) findViewById(R.id.id_progress);
        show = (ImageView) findViewById(R.id.id_show);
        final Handler handler = new Handler(){
            public void handleMessage(Message msg){
                if(msg.what == 0x123){
                    if(mDownStatus == 100){
                        Toast.makeText(MainActivity.this, "download task done", Toast.LENGTH_SHORT).show();
                        Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/a.chm");
                        show.setImageBitmap(bitmap);
                    }
                    bar.setProgress(mDownStatus);
                }
            }
        };
        btn_download.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                downUtill = new DownUtil(url.getText().toString(),target.getText().toString(),6);
                Log.i("KKK",url.getText().toString()+"-----"+target.getText().toString());
                new Thread(){
                    public void run(){
                        downUtill.download();
                        final Timer timer = new Timer();
                        timer.schedule(new TimerTask() {
                            @Override
                            public void run() {
                                double completeRate = downUtill.getConpleteRate();
                                mDownStatus = (int) completeRate * 100;
                                Log.i("KKK",mDownStatus+"%");
                                handler.sendEmptyMessage(0x123);
                                if(mDownStatus>=100){
                                    Log.i("KKK","下载完成");
                                    timer.cancel();
                                }
                            }
                        },0,100);
                    }

                }.start();
            }
        });
    }
}
注意事项:需要在AndroidManifest.xml中定义如下权限:
<uses-permission android:name="android.permission.INTERNET"/>     联网权限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>     创建删除文件权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>    写入SD卡权限
所出现的问题:
     1.  is.getContentLength结果为0,可能是要下载的资源没有给出下载权限 或是服务器没有给出Content-Length字段,需要换一个资源下载进行测试。
     2.  getContentLength返回结果-1,可能是缺少  conn.setRequestProperty("Accept-Encoding","identity");这行代码。






  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值