使用AsyncTask实现断点续传,Android中的异步任务

早前集团内部项目标下载模块都是行使xUtils提供的,近些日子看了下xUtils的源码,它里面也是接收AsyncTask来实施异步职分的,它的下载也包蕴了断点续传的功效。这里笔者自个儿也运用AsyncTask也落到实处了大致的断点续传的作用。

温故而知新,系统一整合治一下。

  首先说一说AsyncTask吧,先来拜见AsyncTask的概念:

异步职责: AsyncTask

在Android中落实异步职务机制有二种情势,Handler和AsyncTask。
  Handler形式需求为每三个任务创立贰个新的线程,职责到位后透过Handler实例向UI线程发送消息,完毕分界面包车型大巴立异,这种格局对于任何经过的支配相比娇小,但也会有缺点的,举例代码相对肥胖,在八个职务同一时间实行时,不易对线程实行标准的调整。
  为了简化操作,Android1.5提供了工具类android.os.AsyncTask,它使创办异步义务变得特别简约,不再供给编写制定任务线程和Handler实例就能够实现相同的职分。AsyncTask的个中贯彻是一个线程池,各种后台职务会付出到线程池中的线程推行,然后利用Thread+Handler的章程调用回调函数。

 public abstract class AsyncTask<Params, Progress, Result> 

1). 理解:

如何是异步职务?
  逻辑上: 以多线程的办法成功的意义要求
  API上: 指AsyncTask类
AsyncTask的理解
  在一贯不AsyncTask早前,
我们用Handler+Thread就足以兑现异步职责的成效需要
  AsyncTask是对Handler和Thread的包装, 使用它更编码更简短,更加高效
  AsyncTask封装了ThreadPool, 比从来动用Thread效用要高

  三种泛型类型分别表示“运维职分推行的输入参数”、“后台职责试行的进度”、“后台计算结果的品种”。在特定场面下,并不是全部品类都被利用,若无被利用,可以用java.lang.Void类型代替。

2). 使用

AsyncTask<Params, Progress, Result>
  Params 运营职务推行的输入参数,比方HTTP乞请的UTiguanL。
  Progress 后台职务施行的比例。
  Result 后台施行任务最终回到的结果,举个例子String。

1.execute(Params…
params卡塔尔(英语:State of Qatar),施行两个异步任务,要求大家在代码中调用此措施,触发异步职分的实行。
  2.onPreExecute(卡塔尔(英语:State of Qatar),在execute(Params…
params卡塔尔国被调用后立马实行,日常用来在实行后台任务前对UI做一些符号。
  3.doInBackground(Params…
params卡塔尔,在onPreExecute(卡塔尔(英语:State of Qatar)达成后任何时候试行,用于推行较为困难的操作,此方式将收到输入参数和再次来到总括结果。在实施进程中能够调用publishProgress(Progress…
values卡塔尔国来更新速度音讯。
  4.onProgressUpdate(Progress…
values卡塔尔(قطر‎,在调用publishProgress(Progress…
values卡塔尔国时,此措施被实践,直接将进度音信更新到UI组件上。
  5.onPostExecute(Result
result卡塔尔,当后台操作甘休时,此办法将会被调用,总结结果将做为参数字传送递到此措施中,直接将结果突显到UI组件上。

  二个异步义务的执行经常满含以下多少个步骤:

3). 注意事项

1.异步任务的实例必需在UI线程中开创。
2.execute(Params… params卡塔尔方法必得在UI线程中调用。
3.永不手动调用onPreExecute(卡塔尔国,doInBackground(Params…
params卡塔尔(قطر‎,onProgressUpdate(Progress… values卡塔尔国,onPostExecute(Result
result卡塔尔(英语:State of Qatar)那多少个艺术。
4.不能够在doInBackground(Params… params卡塔尔(قطر‎中修正UI组件的信息。
5.一个职务实例只可以施行叁次,纵然实施第三遍将会抛出极其。

——相关资料推荐
详解Android中AsyncTask的使用
Android 新闻管理机制原理
Android 异步音信处理体制 令你浓烈通晓Looper、Handler、Message三者关系

  1.execute(Params…
params卡塔尔国,实施三个异步任务,须求大家在代码中调用此措施,触发异步职务的施行。

  2.onPreExecute(卡塔尔,在execute(Params…
params卡塔尔(英语:State of Qatar)被调用后当即实施,平常用来在实践后台任务前对UI做一些标识。

  3.doInBackground(Params…
params卡塔尔,在onPreExecute(卡塔尔(英语:State of Qatar)完毕后立时奉行,用于施行较为困难的操作,此措施将接纳输入参数和重临计算结果。在执行进程中能够调用publishProgress(Progress…
values卡塔尔国来更新速度新闻。

  4.onProgressUpdate(Progress…
values卡塔尔,在调用publishProgress(Progress…
values卡塔尔(قطر‎时,此措施被实施,直接将进度音讯更新到UI组件上。

  5.onPostExecute(Result
result卡塔尔国,当后台操作甘休时,此方法将会被调用,总计结果将做为参数字传送递到此办法中,直接将结果展现到UI组件上。

  在行使的时候,有几点须求卓殊精心:

  1.异步职务的实例必需在UI线程中成立。

  2.execute(Params… params卡塔尔(قطر‎方法必需在UI线程中调用。

  3.不要手动调用onPreExecute(卡塔尔(英语:State of Qatar),doInBackground(Params…
params卡塔尔(قطر‎,onProgressUpdate(Progress… values卡塔尔(英语:State of Qatar),onPostExecute(Result
result卡塔尔(قطر‎那多少个方法。

  4.无法在doInBackground(Params… params卡塔尔(英语:State of Qatar)中改良UI组件的新闻。

  5.一个职责实例只可以实行一回,就算推行第一回将会抛出非常。

  上边是应用AsyncTask完成断点续传的代码:

  断点续传的思绪其实也挺简单,首先判定待下载的文本在本地是不是留存,要是存在,则代表该文件已经下载过一片段了,只须要拿到文件当前高低即已下载大小,设置给http的header就能够了:

 Header header_size = new BasicHeader("Range", "bytes=" + readedSize + "-");
 request.addHeader(header_size); 

  1、结构文件代码:

<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:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".AsyncTaskDemoActivity"
  android:orientation="vertical">
  <Button
    android:id="@+id/begin"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="开始下载"/>
  <Button
    android:id="@+id/end"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="暂停下载"/>
  <ProgressBar
    android:id="@+id/progressbar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="3dp"
    android:layout_marginTop="10dp"
    android:max="100" />
</LinearLayout>

结构比较容易,就多个按键和三个进程条控件,按键调控下载与暂停。

  2、断点续传焦点代码:

package com.bbk.lling.myapplication;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
public class AsyncTaskDemoActivity extends Activity {
  private ProgressBar progressBar;
  //下载路径
  private String downloadPath = Environment.getExternalStorageDirectory() +
      File.separator + "download";
  private DownloadAsyncTask downloadTask;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_async_task_demo);
    progressBar = (ProgressBar) findViewById(R.id.progressbar);
    //开始下载
    findViewById(R.id.begin).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        /**
         * 一个AsyncTask只能被执行一次,否则会抛异常
         * java.lang.IllegalStateException: Cannot execute task: the task is already running.
         * 如果要重新开始任务的话要重新创建AsyncTask对象
         */
        if(downloadTask != null && !downloadTask.isCancelled()) {
          return;
        }
        downloadTask = new DownloadAsyncTask("http://bbk-lewen.u.qiniudn.com/3d5b1a2c-4986-4e4a-a626-b504a36e600a.flv");
        downloadTask.execute();
      }
    });
    //暂停下载
    findViewById(R.id.end).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if(downloadTask != null && downloadTask.getStatus() == AsyncTask.Status.RUNNING) {
          downloadTask.cancel(true);
        }
      }
    });
  }
  /**
   * 下载的AsyncTask
   */
  private class DownloadAsyncTask extends AsyncTask<String, Integer, Long> {
    private static final String TAG = "DownloadAsyncTask";
    private String mUrl;
    public DownloadAsyncTask(String url) {
      this.mUrl = url;
    }
    @Override
    protected Long doInBackground(String... params) {
      Log.i(TAG, "downloading");
      if(mUrl == null) {
        return null;
      }
      HttpClient client = new DefaultHttpClient();
      HttpGet request = new HttpGet(mUrl);
      HttpResponse response = null;
      InputStream is = null;
      RandomAccessFile fos = null;
      OutputStream output = null;
      try {
        //创建存储文件夹
        File dir = new File(downloadPath);
        if(!dir.exists()) {
          dir.mkdir();
        }
        //本地文件
        File file = new File(downloadPath + File.separator + mUrl.substring(mUrl.lastIndexOf("/") + 1));
        if(!file.exists()){
          //创建文件输出流
          output = new FileOutputStream(file);
          //获取下载输入流
          response = client.execute(request);
          is = response.getEntity().getContent();
          //写入本地
          file.createNewFile();
          byte buffer [] = new byte[1024];
          int inputSize = -1;
          //获取文件总大小,用于计算进度
          long total = response.getEntity().getContentLength();
          int count = 0; //已下载大小
          while((inputSize = is.read(buffer)) != -1) {
            output.write(buffer, 0, inputSize);
            count += inputSize;
            //更新进度
            this.publishProgress((int) ((count / (float) total) * 100));
            //一旦任务被取消则退出循环,否则一直执行,直到结束
            if(isCancelled()) {
              output.flush();
              return null;
            }
          }
          output.flush();
        } else {
          long readedSize = file.length(); //文件大小,即已下载大小
          //设置下载的数据位置XX字节到XX字节
          Header header_size = new BasicHeader("Range", "bytes=" + readedSize + "-");
          request.addHeader(header_size);
          //执行请求获取下载输入流
          response = client.execute(request);
          is = response.getEntity().getContent();
          //文件总大小=已下载大小+未下载大小
          long total = readedSize + response.getEntity().getContentLength();
          //创建文件输出流
          fos = new RandomAccessFile(file, "rw");
          //从文件的size以后的位置开始写入,其实也不用,直接往后写就可以。有时候多线程下载需要用
          fos.seek(readedSize);
          //这里用RandomAccessFile和FileOutputStream都可以,只是使用FileOutputStream的时候要传入第二哥参数true,表示从后面填充
//          output = new FileOutputStream(file, true);
          byte buffer [] = new byte[1024];
          int inputSize = -1;
          int count = (int)readedSize;
          while((inputSize = is.read(buffer)) != -1) {
            fos.write(buffer, 0, inputSize);
//            output.write(buffer, 0, inputSize);
            count += inputSize;
            this.publishProgress((int) ((count / (float) total) * 100));
            if(isCancelled()) {
//              output.flush();
              return null;
            }
          }
//          output.flush();
        }
      } catch (MalformedURLException e) {
        Log.e(TAG, e.getMessage());
      } catch (IOException e) {
        Log.e(TAG, e.getMessage());
      } finally{
        try{
          if(is != null) {
            is.close();
          }
          if(output != null) {
            output.close();
          }
          if(fos != null) {
            fos.close();
          }
        } catch(Exception e) {
          e.printStackTrace();
        }
      }
      return null;
    }
    @Override
    protected void onPreExecute() {
      Log.i(TAG, "download begin ");
      Toast.makeText(AsyncTaskDemoActivity.this, "开始下载", Toast.LENGTH_SHORT).show();
      super.onPreExecute();
    }
    @Override
    protected void onProgressUpdate(Integer... values) {
      super.onProgressUpdate(values);
      Log.i(TAG, "downloading " + values[0]);
      //更新界面进度条
      progressBar.setProgress(values[0]);
    }
    @Override
    protected void onPostExecute(Long aLong) {
      Log.i(TAG, "download success " + aLong);
      Toast.makeText(AsyncTaskDemoActivity.this, "下载结束", Toast.LENGTH_SHORT).show();
      super.onPostExecute(aLong);
    }
  }
}

这么总结的断点续传作用就完毕了,这里只是单个线程的,假设波及多个线程同一时候下载,那复杂比超级多,后边再切磋商量。

源码下载:

总结

如上所述是小编给大家介绍的Android
使用AsyncTask达成断点续传,希望对我们全数利于,假若我们有此外疑问请给自身留言,我会及时过来咱们的。在那也极度感激大家对剧本之家网址的支撑!

你可能感兴趣的篇章:

  • Android
    使用AsyncTask达成多任务三十二线程断点续传下载
  • Android多线程AsyncTask详解
  • android使用AsyncTask达成四线程下载实例
  • Android使用AsyncTask实现多线程下载的法子
  • Android开辟笔记之:深刻掌握四十四线程AsyncTask
  • Android
    使用AsyncTask达成八线程断点续传

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注