Android应用开发:网络编程2

网络编程

1. 使用HttpClient发送get请求

HttpClient是Apache开发的第三方框架,Google把它封装到了Android API中,用于发送HTTP请求。

在Android.jar包中,可以看到有很多java的API,这些都是被Android改写的API,也可以看到Android封装了大量的Apache API。

img
img
img

示例:res\layout\activity_main.xml

<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"
    tools:context=".MainActivity" 
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <EditText
        android:id="@+id/et_pass"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="get登陆"
        android:onClick="click1"
        />
    
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="post登陆"
        android:onClick="click2"
        />
</LinearLayout>

src/cn.itcast.getmethod/MainActivity.java

package cn.itcast.getmethod;

import java.io.InputStream;
import java.net.URLEncoder;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import cn.itcast.getmethod.tool.Tools;

public class MainActivity extends Activity {

        Handler handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                        Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();
                }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }
        
        public void click1(View v){
                
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                String name = et_name.getText().toString();
                String pass = et_pass.getText().toString();
                
                final String path = "http://192.168.1.100:8080/Web/servlet/Login?name=" + URLEncoder.encode(name) + "&pass=" + pass;
                
                Thread t = new Thread(){
                        @Override
                        public void run() {
                                //1. 创建客户端对象
                                //HttpClient是一个接口,不要new一个HttpClient对象,否则要实现很多的方法
                                HttpClient client = new DefaultHttpClient();
                                
                                //2. 创建Http GET请求对象
                                HttpGet get = new HttpGet(path);
                                
                                try {
                                        //3. 使用客户端发送get请求
                                        HttpResponse response = client.execute(get);
                                        //获取状态行
                                        StatusLine line = response.getStatusLine();
                                        //从状态行中拿到状态码
                                        if(line.getStatusCode() == 200){
                                                //获取实体,实体里存放的是服务器返回的数据的相关信息
                                                HttpEntity entity = response.getEntity();
                                                //获取服务器返回的输入流
                                                InputStream is = entity.getContent();
                                                
                                                String text = Tools.getTextFromStream(is);
                                                
                                                //发送消息,让主线程刷新UI
                                                Message msg = handler.obtainMessage();
                                                msg.obj = text;
                                                handler.sendMessage(msg);
                                        }
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                };
                t.start();
        }
}

添加权限:

img

点击get登陆按钮,运行结果:

img

2. 使用HttpClient发送post请求

src/cn.itcast.postmethod/MainActivity.java

package cn.itcast.postmethod;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import cn.itcast.getmethod.R;
import cn.itcast.getmethod.tool.Tools;

public class MainActivity extends Activity {

        Handler handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                        Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();
                }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }
        
        public void click2(View v){
                
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                final String name = et_name.getText().toString();
                final String pass = et_pass.getText().toString();
                
                final String path = "http://:8080/Web/servlet/Login";
                
                Thread t = new Thread(){
                        @Override
                        public void run() {
                                //1. 创建客户端对象
                                HttpClient client = new DefaultHttpClient();
                                
                                //2. 创建Http POST请求对象
                                HttpPost post = new HttpPost(path);
                                
                                try{
                                        //通过此集合封装要提交的数据
                                        List<NameValuePair> parameters = new ArrayList<NameValuePair>();
                                        
                                        //集合的泛型是BasicNameValuePair类型,那么由此可以推算出,要提交的数据是封装在BasicNameValuePair对象中
                                        BasicNameValuePair bvp1 = new BasicNameValuePair("name", name);
                                        BasicNameValuePair bvp2 = new BasicNameValuePair("pass", pass);
                                        
                                        parameters.add(bvp1);
                                        parameters.add(bvp2);
                                        
                                        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters,"utf-8");
                                        //把实体类封装至post请求中,提交post请求时,实体中的数据就会用输出流写给服务器
                                        post.setEntity(entity);
                                        
                                        //客户端发送post请求
                                        HttpResponse response = client.execute(post);
                                        
                                        //获取状态行
                                       StatusLine line = response.getStatusLine();
                                       //从状态行中拿到状态码
                                       if(line.getStatusCode() == 200){
                                              //获取实体,实体里存放的是服务器返回的数据的相关信息
                                               HttpEntity et = response.getEntity();
                                               //获取服务器返回的输入流
                                               InputStream is = et.getContent();
                            
                                               String text = Tools.getTextFromStream(is);
                            
                                               //发送消息,让主线程刷新UI
                                               Message msg = handler.obtainMessage();
                                               msg.obj = text;
                                              handler.sendMessage(msg);
                                      }
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                };
                t.start();
        }
}

点击post登陆按钮,运行结果:

img

3. 异步HttpClient框架

从github上下载android-async-http-master开源jar包,拷贝library/src/main/java目录下的内容到我们自己的项目中。

img
img

拷贝后,发现有错误,这是由于Base64.java中的BuildConfig类导包问题,Ctrl+Shift+O自动导包即可修复。


img
img
img

使用异步HttpClient框架实现上面示例中的功能,activity.xml与上面的示例相同,修改MainActivity.java代码。
src/cn.itcast.asynchttpclient/MainActivity.java

package cn.itcast.asynchttpclient;

import org.apache.http.Header;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

public class MainActivity extends Activity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }
        
        public void click1(View v){
                
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                final String name = et_name.getText().toString();
                final String pass = et_pass.getText().toString();
                
                final String path = "http://192.168.1.100:8080/Web/servlet/Login";
                
                //使用异步HttpClient发送get请求
                AsyncHttpClient client = new AsyncHttpClient();
                
                //定义一个请求参数对象,封装要提交的数据
                RequestParams rp = new RequestParams();
                rp.add("name", name);
                rp.add("pass", pass);
                
                //发送get请求
                client.get(path, rp, new MyResponseHandler());
        }
        
        public void click2(View v){
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                final String name = et_name.getText().toString();
                final String pass = et_pass.getText().toString();
                
                final String path = "http://192.168.1.100:8080/Web/servlet/Login";
                
                AsyncHttpClient client = new AsyncHttpClient();
                
                RequestParams rp = new RequestParams();
                rp.add("name", name);
                rp.add("pass", pass);
                
                //发送post请求
                client.post(path, rp, new MyResponseHandler());
        }
        
        class MyResponseHandler extends AsyncHttpResponseHandler{

                //请求成功时(响应码为200开头),此方法调用
                //登陆成功或者登录失败,只要请求成功,都会调用onSuccess方法
                @Override
                public void onSuccess(int statusCode, Header[] headers,
                                byte[] responseBody) {
                        Toast.makeText(MainActivity.this, new String(responseBody), 0).show();
                }

                //请求失败时(响应码非200开头)调用
                @Override
                public void onFailure(int statusCode, Header[] headers,
                                byte[] responseBody, Throwable error) {
                        //请求不成功,也显示登录失败
                        Toast.makeText(MainActivity.this, "登陆失败", 0).show();
                }
        }
}

添加权限:

img

运行结果:分别点击“get登陆”和“post登陆”按钮。

img

4. 多线程下载的原理和过程

断点续传:上次下载到哪,这次就从哪开始下。
多线程:下载速度更快。
原理:抢占服务器资源。例如:带宽为20M/s,3个人去下载同一部电影,那么每人分别占6.66M/s带宽。如果有一人A开了3个线程同时下载,那么5个线程,各占4M/s带宽,那么A所占带宽就是4*3=12M/s,其他两人各占4M/s带宽。也就是说A抢占了更多的服务器资源。

img

多线程下载示例说明:
例如有一个10KB的文件,分成010,3个线程去下载,第0个线程下载02,也就是3KB数据,第1个线程下载35,也就是3KB数据,余下的69,4KB的数据由最后一个线程下载。

总结出公式就是:
每个线程下载的数据开始点:threadId*size,结束点:(threadId + 1) * size -1。

最后一个线程除外,下载结束点:length - 1。

计算每条线程的下载区间

多线程断点续传的API全部都是Java API,Java项目测试比较容易,所以,我们先创建一个Java项目。
将待下载的资源放入Tomcat服务器中。

img
img

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        //打开连接对象,做初始化设置
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                //获取要下载的目标文件的总长度
                                int length = conn.getContentLength();
                                
                                //计算每条线程要下载的长度
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                //计算每条线程下载的开始位置和结束位置
                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        //如果是最后一条线程,那么需要把余数也一块下载
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
}

运行结果:

img

创建临时文件
src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                //创建一个与目标文件大小一致的临时文件
                                File file = new File(getFileNameFromPath(path));
                                //打开文件的访问模式设置为rwd,表示除了读取和写入,还要求对文件内容的每个更新都同步写入到底层存储设备。
                                //设计到下载的程序,文件访问模式一定要使用rwd,不经过缓冲区,直接写入硬盘。
                                //如果下载到的数据让写入到缓冲区,一旦断电,缓冲区数据丢失,并且下次服务器断点续传也不会再传输这部分数据,那么下载的文件就不能用了
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                //设置临时文件的大小
                                raf.setLength(length);
                                
                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

开启多个线程下载文件

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                                        
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                URL url;
                try{
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        //Range表示指定请求的数据区间
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        //请求部分数据,返回的是206
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                //打开临时文件的IO流
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                //修改写入临时文件的开始位置
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                //当前线程下载的总进度
                                int total = 0;
                                while((len = is.read(b)) != -1){
                                        //把读取到的字节写入临时文件中
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("线程" + threadId + "下载的进度为:" + total);
                                }
                                raf.close();
                        }
                        System.out.println("线程" + threadId + "下载完毕---------------------");
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

运行结果:刷新,即可看到文件已经下载好了

img
img
img
img

创建进度临时文件保存下载进度

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                                        
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                URL url;
                try{
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                int total = 0;
                                while((len = is.read(b)) != -1){
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("线程" + threadId + "下载的进度为:" + total);
                                        
                                        //创建一个进度临时文件,保存下载进度
                                        File fileProgress = new File(threadId + ".txt");
                                        RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                        rafProgress.write((total + "").getBytes());
                                        rafProgress.close();
                                }
                                raf.close();
                        }
                        System.out.println("线程" + threadId + "下载完毕---------------------");
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

运行结果:执行程序,然后,在没下载完成时,就点击右上角的停止按钮。

img

刷新,可以看到记录文件已经产生。

img
img

完成断点续传下载

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

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;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                
                URL url;
                
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                
                URL url;
                
                try{
                        int lastProgress = 0;
                        //下载之前,先判断进度临时文件是否存在
                        File fileProgress1 = new File(threadId + ".txt");
                        if(fileProgress1.exists()){
                                FileInputStream fis = new FileInputStream(fileProgress1);
                                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                //读取进度临时文件中的值
                                lastProgress = Integer.parseInt(br.readLine());
                                //把上一次下载的进度加到下载开始位置
                                startIndex += lastProgress;
                                fis.close();
                        }
                        
                        System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                        
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                //从之前下载的地方开始下载
                                int total = lastProgress;
                                while((len = is.read(b)) != -1){
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("线程" + threadId + "下载的进度为:" + total);
                                        
                                        File fileProgress = new File(threadId + ".txt");
                                        RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                        rafProgress.write((total + "").getBytes());
                                        rafProgress.close();
                                }
                                raf.close();
                                System.out.println("线程" + threadId + "下载完毕---------------------");
                        }
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

运行结果:

执行Main.java程序,然后,在还没有下载完,停止。然后,再次执行Main.java,可以看到如下显示,也就是实现了断点续传。

img

下载后删除进度临时文件
src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

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;

public class Main {

        //记录当前已经下载完成的线程的数量
        static int finishedThreadCount = 0;
        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                
                URL url;
                
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                
                URL url;
                
                try{
                        int lastProgress = 0;
                        File fileProgress1 = new File(threadId + ".txt");
                        if(fileProgress1.exists()){
                                FileInputStream fis = new FileInputStream(fileProgress1);
                                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                lastProgress = Integer.parseInt(br.readLine());
                                startIndex += lastProgress;
                                fis.close();
                        }
                        
                        System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                        
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                int total = lastProgress;
                                while((len = is.read(b)) != -1){
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("线程" + threadId + "下载的进度为:" + total);
                                        
                                        File fileProgress = new File(threadId + ".txt");
                                        RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                        rafProgress.write((total + "").getBytes());
                                        rafProgress.close();
                                }
                                raf.close();
                                System.out.println("线程" + threadId + "下载完毕---------------------");
                                
                                //在所有线程都下载完毕后,一起删除所有进度临时文件
                                //有一个线程完成下载,已经下载完成的线程的数量+1
                                Main.finishedThreadCount++;

                                synchronized(Main.path){
                                        if(Main.finishedThreadCount == 3){
                                                //删除所有进度临时文件
                                                for(int i = 0; i < Main.finishedThreadCount; i++){
                                                        File f = new File(i + ".txt");
                                                        f.delete();
                                                }
                                                //为了防止所有线程都执行到上面的Main.finishedThreadCount++;,然后三个线程都执行删除所有临时文件的代码。
                                                //所以,一方面使用同步代码块,另一方面将Main.finishedThreadCount设置为0。
                                                Main.finishedThreadCount = 0;
                                        }
                                }
                        }
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

运行结果:运行Main.java,断点续传完成后,刷新。可以看到,临时文件已经被删除。

img

5. Android版多线程断点续传下载

res/layout/activity.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"
    tools:context=".MainActivity" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载"
        android:onClick="click" />

</RelativeLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.androidmultidownload;

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.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;

public class MainActivity extends Activity {

        int finishedThreadCount = 0;
        int threadCount = 3;
        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }

    public void click(View v){
            Thread t = new Thread(){
                    @Override
                    public void run() {

                            URL url;
                            
                            try {
                                    url = new URL(path);
                                    
                                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                    conn.setConnectTimeout(8000);
                                    conn.setReadTimeout(8000);
                                    
                                    if(conn.getResponseCode() == 200){
                                            int length = conn.getContentLength();
                                            
                                            int size = length / threadCount;
                                            System.out.println("size:" + size);

                                            for(int threadId = 0; threadId < threadCount; threadId++){
                                                    int startIndex = threadId * size;
                                                    int endIndex = (threadId + 1) * size - 1;
                                                    
                                                    if(threadId == threadCount - 1){
                                                            endIndex = length - 1;
                                                    }
                                                    DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                                    dt.start();
                                            }
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
            };
            t.start();
    }
    
        public String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
        
        class DownLoadThread extends Thread{
                int threadId;
                int startIndex;
                int endIndex;
                
                public DownLoadThread(int threadId, int startIndex, int endIndex) {
                        super();
                        this.threadId = threadId;
                        this.startIndex = startIndex;
                        this.endIndex = endIndex;
                }
                
                public void run(){
                        
                        URL url;
                        
                        try{
                                int lastProgress = 0;
                                //修改文件路径,存在外部存储器中
                                File fileProgress1 = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                if(fileProgress1.exists()){
                                        FileInputStream fis = new FileInputStream(fileProgress1);
                                        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                        lastProgress = Integer.parseInt(br.readLine());
                                        startIndex += lastProgress;
                                        fis.close();
                                }
                                
                                System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                                
                                url = new URL(path);
                                
                                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                conn.setConnectTimeout(8000);
                                conn.setReadTimeout(8000);
                                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                                
                                if(conn.getResponseCode() == 206){
                                        InputStream is = conn.getInputStream();
                                        
                                        File file = new File(Environment.getExternalStorageDirectory(), getFileNameFromPath(path));
                                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                        raf.seek(startIndex);
                                        
                                        byte[] b = new byte[1024];
                                        int len = 0;
                                        int total = lastProgress;
                                        while((len = is.read(b)) != -1){
                                                raf.write(b, 0, len);
                                                total += len;
                                                System.out.println("线程" + threadId + "下载的进度为:" + total);
                                                
                                                File fileProgress = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                                RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                                rafProgress.write((total + "").getBytes());
                                                rafProgress.close();
                                        }
                                        raf.close();
                                        System.out.println("线程" + threadId + "下载完毕---------------------");
                                        
                                        finishedThreadCount++;

                                        synchronized(path){
                                                if(finishedThreadCount == 3){
                                                        for(int i = 0; i < finishedThreadCount; i++){
                                                                File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
                                                                f.delete();
                                                        }
                                                        finishedThreadCount = 0;
                                                }
                                        }
                                }
                        }catch(Exception e){
                                e.printStackTrace();
                        }
                }
        }
}

添加权限:


img

运行结果:点击“下载”按钮,在下载完成之前,杀死线程。

img
img

可以看到临时文件生成。


img
img

再次运行应用程序,点击“下载”按钮,接着下载,断点续传成功实现。

img

下载完成后,可以看到临时文件删除成功。

img

添加进度条反应下载进度,res/layout/activity.xml

<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"
    tools:context=".MainActivity" 
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载"
        android:onClick="click" />

    <ProgressBar 
        android:id="@+id/pb"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    
</LinearLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.androidmultidownload;

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.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ProgressBar;

public class MainActivity extends Activity {

        int finishedThreadCount = 0;
        int threadCount = 3;
        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        private ProgressBar pb;
        //记录进度条的当前进度
        int currentProgress = 0;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                //进度条
                pb = (ProgressBar) findViewById(R.id.pb);
        }

    public void click(View v){
            Thread t = new Thread(){
                    @Override
                    public void run() {

                            URL url;
                            
                            try {
                                    url = new URL(path);
                                    
                                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                    conn.setConnectTimeout(8000);
                                    conn.setReadTimeout(8000);
                                    
                                    if(conn.getResponseCode() == 200){
                                            int length = conn.getContentLength();
                                            
                                            //设定进度条的最大值
                                            pb.setMax(length);
                                            
                                            int size = length / threadCount;
                                            System.out.println("size:" + size);

                                            for(int threadId = 0; threadId < threadCount; threadId++){
                                                    int startIndex = threadId * size;
                                                    int endIndex = (threadId + 1) * size - 1;
                                                    
                                                    if(threadId == threadCount - 1){
                                                            endIndex = length - 1;
                                                    }
                                                    DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                                    dt.start();
                                            }
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
            };
            t.start();
    }
    
        public String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
        
        class DownLoadThread extends Thread{
                int threadId;
                int startIndex;
                int endIndex;
                
                public DownLoadThread(int threadId, int startIndex, int endIndex) {
                        super();
                        this.threadId = threadId;
                        this.startIndex = startIndex;
                        this.endIndex = endIndex;
                }
                
                public void run(){
                        
                        URL url;
                        
                        try{
                                int lastProgress = 0;
                                File fileProgress1 = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                if(fileProgress1.exists()){
                                        FileInputStream fis = new FileInputStream(fileProgress1);
                                        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                        lastProgress = Integer.parseInt(br.readLine());
                                        startIndex += lastProgress;
                                        
                                        //如果开始位置大于或等于endIndex,说明上一次下载中,此线程就已经下载完了
                                        if(startIndex >= endIndex){
                                                finishedThreadCount++;
                                        }
                                        
                                        //如果上一次下载过,把上次的进度加到当前进度中
                                        currentProgress += lastProgress;
                                        pb.setProgress(currentProgress);
                                        fis.close();
                                }
                                
                                System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                                
                                url = new URL(path);
                                
                                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                conn.setConnectTimeout(8000);
                                conn.setReadTimeout(8000);
                                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                                
                                if(conn.getResponseCode() == 206){
                                        InputStream is = conn.getInputStream();
                                        
                                        File file = new File(Environment.getExternalStorageDirectory(), getFileNameFromPath(path));
                                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                        raf.seek(startIndex);
                                        
                                        byte[] b = new byte[1024];
                                        int len = 0;
                                        int total = lastProgress;
                                        while((len = is.read(b)) != -1){
                                                raf.write(b, 0, len);
                                                total += len;
                                                
                                                System.out.println("线程" + threadId + "下载的进度为:" + total);
                                                
                                                File fileProgress = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                                RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                                rafProgress.write((total + "").getBytes());
                                                rafProgress.close();
                                                
                                                //每一条线程下载的数据,都应该加到全局进度里
                                                currentProgress += len;
                                                //设置进度条当前进度
                                                //进度条内部也是通过handler让主线程刷新UI的
                                                pb.setProgress(currentProgress);
                                        }
                                        raf.close();
                                        System.out.println("线程" + threadId + "下载完毕---------------------");
                                        
                                        finishedThreadCount++;

                                        synchronized(path){
                                                if(finishedThreadCount == 3){
                                                        for(int i = 0; i < finishedThreadCount; i++){
                                                                File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
                                                                f.delete();
                                                        }
                                                        finishedThreadCount = 0;
                                                }
                                        }
                                }
                        }catch(Exception e){
                                e.printStackTrace();
                        }
                }
        }
}

运行结果:点击“下载”按钮,可以通过进度条看到下载进度。然后,杀死进程,再重新运行应用程序,点击“下载”按钮,可以看到进度条在原有的基础上继续向前移动,也就是实现了断点续传的进度条实现。

img

添加文本进度,res/layout/activity.xml

<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"
    tools:context=".MainActivity" 
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载"
        android:onClick="click" />

    <ProgressBar 
        android:id="@+id/pb"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    
    <TextView 
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0%"
        android:layout_gravity="right"
        />
    
</LinearLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.androidmultidownload;

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.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

        int finishedThreadCount = 0;
        int threadCount = 3;
        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        private ProgressBar pb;
        int currentProgress = 0;
        
        private TextView tv;
        
        //刷新TextView
        Handler handler = new Handler(){
                public void handleMessage(android.os.Message msg) {
                        //当前进度除以最大进度,得到下载进度的百分比
                        tv.setText(pb.getProgress() * 100 /pb.getMax() + "%");
                }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                pb = (ProgressBar) findViewById(R.id.pb);
                tv = (TextView)findViewById(R.id.tv);
        }

    public void click(View v){
            Thread t = new Thread(){
                    @Override
                    public void run() {

                            URL url;
                            
                            try {
                                    url = new URL(path);
                                    
                                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                    conn.setConnectTimeout(8000);
                                    conn.setReadTimeout(8000);
                                    
                                    if(conn.getResponseCode() == 200){
                                            int length = conn.getContentLength();
                                            
                                            pb.setMax(length);
                                            
                                            int size = length / threadCount;
                                            System.out.println("size:" + size);

                                            for(int threadId = 0; threadId < threadCount; threadId++){
                                                    int startIndex = threadId * size;
                                                    int endIndex = (threadId + 1) * size - 1;
                                                    
                                                    if(threadId == threadCount - 1){
                                                            endIndex = length - 1;
                                                    }
                                                    DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                                    dt.start();
                                            }
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
            };
            t.start();
    }
    
        public String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
        
        class DownLoadThread extends Thread{
                int threadId;
                int startIndex;
                int endIndex;
                
                public DownLoadThread(int threadId, int startIndex, int endIndex) {
                        super();
                        this.threadId = threadId;
                        this.startIndex = startIndex;
                        this.endIndex = endIndex;
                }
                
                public void run(){
                        
                        URL url;
                        
                        try{
                                int lastProgress = 0;
                                File fileProgress1 = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                if(fileProgress1.exists()){
                                        FileInputStream fis = new FileInputStream(fileProgress1);
                                        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                        lastProgress = Integer.parseInt(br.readLine());
                                        startIndex += lastProgress;
                                        
                                        if(startIndex >= endIndex){
                                                finishedThreadCount++;
                                        }
                                        
                                        currentProgress += lastProgress;
                                        pb.setProgress(currentProgress);
                                        
                                        //发送消息,让主线程刷新文本进度
                                        handler.sendEmptyMessage(1);
                                        fis.close();
                                }
                                
                                System.out.println("线程" + threadId + ",下载区间为:" + startIndex + "-" + endIndex);
                                
                                url = new URL(path);
                                
                                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                conn.setConnectTimeout(8000);
                                conn.setReadTimeout(8000);
                                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                                
                                if(conn.getResponseCode() == 206){
                                        InputStream is = conn.getInputStream();
                                        
                                        File file = new File(Environment.getExternalStorageDirectory(), getFileNameFromPath(path));
                                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                        raf.seek(startIndex);
                                        
                                        byte[] b = new byte[1024];
                                        int len = 0;
                                        int total = lastProgress;
                                        while((len = is.read(b)) != -1){
                                                raf.write(b, 0, len);
                                                total += len;
                                                
                                                System.out.println("线程" + threadId + "下载的进度为:" + total);
                                                
                                                File fileProgress = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                                RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                                rafProgress.write((total + "").getBytes());
                                                rafProgress.close();
                                                
                                                currentProgress += len;
                                                pb.setProgress(currentProgress);
                                                
                                                //发送消息,让主线程刷新文本进度
                                                handler.sendEmptyMessage(1);
                                        }
                                        raf.close();
                                        System.out.println("线程" + threadId + "下载完毕---------------------");
                                        
                                        finishedThreadCount++;

                                        synchronized(path){
                                                if(finishedThreadCount == 3){
                                                        for(int i = 0; i < finishedThreadCount; i++){
                                                                File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
                                                                f.delete();
                                                        }
                                                        finishedThreadCount = 0;
                                                }
                                        }
                                }
                        }catch(Exception e){
                                e.printStackTrace();
                        }
                }
        }
}

运行结果:

img

文本进度计算的bug:当文件较大时,就会出现bug,文本进度计算数据变成了负数。

img

这是因为文件大小超出了int所能表示的最大范围。

img

只需要修改代码如下即可。

img

如果最终显示为99%,那么只需要在下载完成之后,直接在程序中写死为100%即可。

6. xUtils多线程断点续传下载

从github上下载xUtils,将xUtils的jar复制到libs目录下。

img
img

如果无法关联源码,可以通过在libs目录下新建一个properties文件解决。

img

properties文件的内容为"src=源码目录",即可成功关联源码。

img

res/layout/activity.xml

<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=".MainActivity" 
    android:orientation="vertical"
    >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载"
        android:onClick="click" />
    
    <TextView 
            android:id="@+id/tv_success"
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
    
    <TextView 
            android:id="@+id/tv_failure"
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ff0000"
    />
    
    <ProgressBar 
            android:id="@+id/tv_pb"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_width="match_parent"
        android:layout_height="wrap_content"
    />

    <TextView 
            android:id="@+id/tv_progress"
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
</LinearLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.xutils;

import java.io.File;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.HttpHandler;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;

public class MainActivity extends Activity {

        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        private TextView tv;
        private ProgressBar pb;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                pb = (ProgressBar)findViewById(R.id.tv_pb);
                tv = (TextView)findViewById(R.id.tv_progress);
        }

    public void click(View v){
            HttpUtils utils = new HttpUtils();
            
            HttpHandler handler = utils.download(path, //请求的网址
                            "sdcard/QQPlayer.exe", //文件保存的路径及文件名
                        true, // 是否支持断点续传
                        true, // 如果相应头中包含文件名,那么下载完毕后,自动以该名字重命名文件
                        new RequestCallBack<File>() {
                    
                                    //下载完成调用
                            @Override
                            public void onSuccess(ResponseInfo<File> responseInfo) {
                                    TextView tv = (TextView)findViewById(R.id.tv_success);
                                    tv.setText(responseInfo.result.getPath());
                            }

                            //下载失败后调用
                            @Override
                            public void onFailure(HttpException error, String msg) {
                                    TextView tv = (TextView)findViewById(R.id.tv_success);
                                    tv.setText(msg);
                            }
                            
                            //下载过程中不断调用
                            @Override
                                    public void onLoading(long total, long current,
                                                    boolean isUploading) {
                                    pb.setMax((int)total);
                                    pb.setProgress((int)current);
                                    tv.setText((current * 100)/ total + "%");
                                    }
                    });
    }
}

添加权限:

img

运行结果:

img
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,443评论 25 707
  • 一.DownloadManager的介绍 1.Android涉及到的网络数据请求,如果是零星数据、且数据量较小(...
    少年的大叔心阅读 2,215评论 0 5
  • 每天都是度日如年,还没毕业就要背负每月1645元的贷款,只好离校找工作,但是处处碰壁,没有一家要我,每次只要技术有...
    心畅密语阅读 166评论 0 0
  • 背叛 是夜,灯火在阑珊,而A城的不夜城的生活才刚刚开始。 不夜城顾名思义一个没有夜晚的地方。不夜城中有一家有名的夜...
    破晓的黎阅读 500评论 0 0
  • 有一天,两位黑帮老大,浩南哥和浩北哥被李Sir抓了起来。李Sir证据不足,便想出了一条妙计。 他把两位大佬分开关押...
    你看得见我阅读 1,807评论 1 4