Android 는 AsyncTask 를 사용 하여 다 중 태 스 크 다 중 스 레 드 정지점 전송 다운 로드 를 실현 합 니 다.

이 블 로 그 는 AsyncTask 다운로드 시리즈 의 마지막 글 입 니 다.앞 에 정지점 속보 와 다 중 스 레 드 다운로드 에 관 한 블 로 그 를 썼 습 니 다.이 블 로 그 는 앞의 두 편 을 바탕 으로 이 루어 졌 습 니 다.관심 있 는 것 은 보 셔 도 됩 니 다.
하나
둘.
여기 서 아 날로 그 앱 다운 로드 는 하나의 Demo 를 실현 했다.하나의 인터페이스 만 있 기 때문에 다운 로드 를 Service 에 넣 지 않 고 Activity 에서 직접 만 들 었 다.정식 프로젝트 에서 다운 로드 는 모두 Service 에 넣 은 다음 에 BroadCast 를 통 해 인터페이스 업데이트 진 도 를 알 립 니 다.
코드 를 올 리 기 전에 데모 의 실행 효과 도 를 보 세 요.

다음은 코드 를 보 겠 습 니 다.이 파일 의 다운로드 정 의 는 다운 로 더 를 정의 하여 이 파일 을 다운로드 하 는 모든 스 레 드(일시 정지,다운로드 등)를 관리 합 니 다.Downloador 는 이 파일 의 특정한 시작 위 치 를 다운로드 하기 위해 3 개의 DownloadTask 를 만 듭 니 다.파일 의 크기 를 통 해 모든 스 레 드 가 다운로드 한 시작 과 끝 위 치 를 계산 하려 면 을 참고 하 십시오.
1.다운 로 더 클래스

package com.bbk.lling.multitaskdownload.downloador;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.bbk.lling.multitaskdownload.beans.AppContent;
import com.bbk.lling.multitaskdownload.beans.DownloadInfo;
import com.bbk.lling.multitaskdownload.db.DownloadFileDAO;
import com.bbk.lling.multitaskdownload.db.DownloadInfoDAO;
import com.bbk.lling.multitaskdownload.utils.DownloadUtils;
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 java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
 * @Class: Downloador
 * @Description:      
 * @author: lling(www.cnblogs.com/liuling)
 * @Date: 2015/10/13
 */
public class Downloador {
 public static final String TAG = "Downloador";
 private static final int THREAD_POOL_SIZE = 9; //      9
 private static final int THREAD_NUM = 3; //    3     
 private static final int GET_LENGTH_SUCCESS = 1;
 public static final Executor THREAD_POOL_EXECUTOR = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
 private List<DownloadTask> tasks;
 private InnerHandler handler = new InnerHandler();
 private AppContent appContent; //      
 private long downloadLength; //            
 private long fileLength;
 private Context context;
 private String downloadPath;
 public Downloador(Context context, AppContent appContent) {
 this.context = context;
 this.appContent = appContent;
 this.downloadPath = DownloadUtils.getDownloadPath();
 }
 /**
 *     
 */
 public void download() {
 if(TextUtils.isEmpty(downloadPath)) {
 Toast.makeText(context, "   SD ", Toast.LENGTH_SHORT).show();
 return;
 }
 if(appContent == null) {
 throw new IllegalArgumentException("download content can not be null");
 }
 new Thread() {
 @Override
 public void run() {
 //      
 HttpClient client = new DefaultHttpClient();
 HttpGet request = new HttpGet(appContent.getUrl());
 HttpResponse response = null;
 try {
  response = client.execute(request);
  fileLength = response.getEntity().getContentLength();
 } catch (Exception e) {
  Log.e(TAG, e.getMessage());
 } finally {
  if (request != null) {
  request.abort();
  }
 }
 //              
 List<DownloadInfo> lists = DownloadInfoDAO.getInstance(context.getApplicationContext())
  .getDownloadInfosByUrl(appContent.getUrl());
 for (DownloadInfo info : lists) {
  downloadLength += info.getDownloadLength();
 }
 //            
 DownloadFileDAO.getInstance(context.getApplicationContext()).insertDownloadFile(appContent);
 Message.obtain(handler, GET_LENGTH_SUCCESS).sendToTarget();
 }
 }.start();
 }
 /**
 *     AsyncTask  
 */
 private void beginDownload() {
 Log.e(TAG, "beginDownload" + appContent.getUrl());
 appContent.setStatus(AppContent.Status.WAITING);
 long blockLength = fileLength / THREAD_NUM;
 for (int i = 0; i < THREAD_NUM; i++) {
 long beginPosition = i * blockLength;//           
 long endPosition = (i + 1) * blockLength;//           
 if (i == (THREAD_NUM - 1)) {
 endPosition = fileLength;//                   ,                    
 }
 DownloadTask task = new DownloadTask(i, beginPosition, endPosition, this, context);
 task.executeOnExecutor(THREAD_POOL_EXECUTOR, appContent.getUrl());
 if(tasks == null) {
 tasks = new ArrayList<DownloadTask>();
 }
 tasks.add(task);
 }
 }
 /**
 *     
 */
 public void pause() {
 for (DownloadTask task : tasks) {
 if (task != null && (task.getStatus() == AsyncTask.Status.RUNNING || !task.isCancelled())) {
 task.cancel(true);
 }
 }
 tasks.clear();
 appContent.setStatus(AppContent.Status.PAUSED);
 DownloadFileDAO.getInstance(context.getApplicationContext()).updateDownloadFile(appContent);
 }
 /**
 *         
 */
 protected synchronized void resetDownloadLength() {
 this.downloadLength = 0;
 }
 /**
 *        
 *         
 * @param size
 */
 protected synchronized void updateDownloadLength(long size){
 this.downloadLength += size;
 //      
 int percent = (int)((float)downloadLength * 100 / (float)fileLength);
 appContent.setDownloadPercent(percent);
 if(percent == 100 || downloadLength == fileLength) {
 appContent.setDownloadPercent(100); //            ,  percent=99
 appContent.setStatus(AppContent.Status.FINISHED);
 DownloadFileDAO.getInstance(context.getApplicationContext()).updateDownloadFile(appContent);
 }
 Intent intent = new Intent(Constants.DOWNLOAD_MSG);
 if(appContent.getStatus() == AppContent.Status.WAITING) {
 appContent.setStatus(AppContent.Status.DOWNLOADING);
 }
 Bundle bundle = new Bundle();
 bundle.putParcelable("appContent", appContent);
 intent.putExtras(bundle);
 context.sendBroadcast(intent);
 }
 protected String getDownloadPath() {
 return downloadPath;
 }
 private class InnerHandler extends Handler {
 @Override
 public void handleMessage(Message msg) {
 switch (msg.what) {
 case GET_LENGTH_SUCCESS :
  beginDownload();
  break;
 }
 super.handleMessage(msg);
 }
 }
}
2,DownloadTask 클래스

package com.bbk.lling.multitaskdownload.downloador;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.bbk.lling.multitaskdownload.beans.DownloadInfo;
import com.bbk.lling.multitaskdownload.db.DownloadInfoDAO;
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.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
/**
 * @Class: DownloadTask
 * @Description:     AsyncTask
 * @author: lling(www.cnblogs.com/liuling)
 * @Date: 2015/10/13
 */
public class DownloadTask extends AsyncTask<String, Integer , Long> {
 private static final String TAG = "DownloadTask";
 private int taskId;
 private long beginPosition;
 private long endPosition;
 private long downloadLength;
 private String url;
 private Downloador downloador;
 private DownloadInfoDAO downloadInfoDAO;
 public DownloadTask(int taskId, long beginPosition, long endPosition, Downloador downloador,
  Context context) {
 this.taskId = taskId;
 this.beginPosition = beginPosition;
 this.endPosition = endPosition;
 this.downloador = downloador;
 downloadInfoDAO = DownloadInfoDAO.getInstance(context.getApplicationContext());
 }
 @Override
 protected void onPreExecute() {
 Log.e(TAG, "onPreExecute");
 }
 @Override
 protected void onPostExecute(Long aLong) {
 Log.e(TAG, url + "taskId:" + taskId + "executed");
// downloador.updateDownloadInfo(null);
 }
 @Override
 protected void onProgressUpdate(Integer... values) {
 //  downloador       
// downloador.updateDownloadLength(values[0]);
 }
 @Override
 protected void onCancelled() {
 Log.e(TAG, "onCancelled");
// downloador.updateDownloadInfo(null);
 }
 @Override
 protected Long doInBackground(String... params) {
 //         :           ,       cancel ,     
 if(isCancelled()) {
 return null;
 }
 url = params[0];
 if(url == null) {
 return null;
 }
 HttpClient client = new DefaultHttpClient();
 HttpGet request = new HttpGet(url);
 HttpResponse response;
 InputStream is;
 RandomAccessFile fos = null;
 OutputStream output = null;
 DownloadInfo downloadInfo = null;
 try {
 //    
 File file = new File(downloador.getDownloadPath() + File.separator + url.substring(url.lastIndexOf("/") + 1));
 //           
 downloadInfo = downloadInfoDAO.getDownloadInfoByTaskIdAndUrl(taskId, url);
 //            
 //      file.exists(),          ,         ,          ,     
 if(file.exists() && downloadInfo != null) {
 if(downloadInfo.isDownloadSuccess() == 1) {
  //        
  return null;
 }
 beginPosition = beginPosition + downloadInfo.getDownloadLength();
 downloadLength = downloadInfo.getDownloadLength();
 }
 if(!file.exists()) {
 //   task     ,         ,            ,    
 downloador.resetDownloadLength();
 }
 //         beginPosition   endPosition  
 Header header_size = new BasicHeader("Range", "bytes=" + beginPosition + "-" + endPosition);
 request.addHeader(header_size);
 //           
 response = client.execute(request);
 is = response.getEntity().getContent();
 //       
 fos = new RandomAccessFile(file, "rw");
 //    size         
 fos.seek(beginPosition);
 byte buffer [] = new byte[1024];
 int inputSize = -1;
 while((inputSize = is.read(buffer)) != -1) {
 fos.write(buffer, 0, inputSize);
 downloadLength += inputSize;
 downloador.updateDownloadLength(inputSize);
 //     ,            
 if (isCancelled()) {
  if(downloadInfo == null) {
  downloadInfo = new DownloadInfo();
  }
  downloadInfo.setUrl(url);
  downloadInfo.setDownloadLength(downloadLength);
  downloadInfo.setTaskId(taskId);
  downloadInfo.setDownloadSuccess(0);
  //          
  downloadInfoDAO.insertDownloadInfo(downloadInfo);
  return null;
 }
 }
 } catch (MalformedURLException e) {
 Log.e(TAG, e.getMessage());
 } catch (IOException e) {
 Log.e(TAG, e.getMessage());
 } finally{
 try{
 if (request != null) {
  request.abort();
 }
 if(output != null) {
  output.close();
 }
 if(fos != null) {
  fos.close();
 }
 } catch(Exception e) {
 e.printStackTrace();
 }
 }
 //     ,   task      
 if(downloadInfo == null) {
 downloadInfo = new DownloadInfo();
 }
 downloadInfo.setUrl(url);
 downloadInfo.setDownloadLength(downloadLength);
 downloadInfo.setTaskId(taskId);
 downloadInfo.setDownloadSuccess(1);
 //          
 downloadInfoDAO.insertDownloadInfo(downloadInfo);
 return null;
 }
}
Downloador 와 DownloadTask 는 이 예 의 핵심 코드 만 있 습 니 다.다음은 데이터베이스 에 관 한 것 입 니 다.정지점 전송 을 실현 하려 면 정지 할 때 모든 스 레 드 가 다운로드 한 위 치 를 기록 해 야 하기 때문에 다음 에 계속 다운로드 할 때 읽 기 편 합 니 다.여기에 두 개의 표 가 있 는데 하 나 는 각 파일 의 다운로드 상 태 를 저장 하 는 것 이 고 하 나 는 각 파일 에 대응 하 는 모든 스 레 드 의 다운로드 상 태 를 저장 하 는 것 이다.
  3、DBHelper

package com.bbk.lling.multitaskdownload.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
 * @Class: DBHelper
 * @Description:       
 * @author: lling(www.cnblogs.com/liuling)
 * @Date: 2015/10/14
 */
public class DBHelper extends SQLiteOpenHelper {
 public DBHelper(Context context) {
 super(context, "download.db", null, 1);
 }
 @Override
 public void onCreate(SQLiteDatabase db) {
 db.execSQL("create table download_info(_id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER, "
 + "download_length INTEGER, url VARCHAR(255), is_success INTEGER)");
 db.execSQL("create table download_file(_id INTEGER PRIMARY KEY AUTOINCREMENT, app_name VARCHAR(255), "
 + "url VARCHAR(255), download_percent INTEGER, status INTEGER)");
 }
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 }
}
4.DownloadFileDAO,파일 다운로드 상태의 데이터베이스 작업 클래스

package com.bbk.lling.multitaskdownload.db;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import android.util.Log;
import com.bbk.lling.multitaskdownload.beans.AppContent;
import java.util.ArrayList;
import java.util.List;
/**
 * @Class: DownloadFileDAO
 * @Description:                  
 * @author: lling(www.cnblogs.com/liuling)
 * @Date: 2015/10/13
 */
public class DownloadFileDAO {
 private static final String TAG = "DownloadFileDAO";
 private static DownloadFileDAO dao=null;
 private Context context;
 private DownloadFileDAO(Context context) {
 this.context=context;
 }
 synchronized public static DownloadFileDAO getInstance(Context context){
 if(dao==null){
 dao=new DownloadFileDAO(context);
 }
 return dao;
 }
 /**
 *        
 * @return
 */
 public SQLiteDatabase getConnection() {
 SQLiteDatabase sqliteDatabase = null;
 try {
 sqliteDatabase= new DBHelper(context).getReadableDatabase();
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 }
 return sqliteDatabase;
 }
 /**
 *     
 * @param appContent
 */
 public void insertDownloadFile(AppContent appContent) {
 if(appContent == null) {
 return;
 }
 //        ,    
 if(getAppContentByUrl(appContent.getUrl()) != null) {
 updateDownloadFile(appContent);
 return;
 }
 SQLiteDatabase database = getConnection();
 try {
 String sql = "insert into download_file(app_name, url, download_percent, status) values (?,?,?,?)";
 Object[] bindArgs = { appContent.getName(), appContent.getUrl(), appContent.getDownloadPercent()
  , appContent.getStatus().getValue()};
 database.execSQL(sql, bindArgs);
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 }
 }
 /**
 *   url        
 * @param url
 * @return
 */
 public AppContent getAppContentByUrl(String url) {
 if(TextUtils.isEmpty(url)) {
 return null;
 }
 SQLiteDatabase database = getConnection();
 AppContent appContent = null;
 Cursor cursor = null;
 try {
 String sql = "select * from download_file where url=?";
 cursor = database.rawQuery(sql, new String[] { url });
 if (cursor.moveToNext()) {
 appContent = new AppContent(cursor.getString(1), cursor.getString(2));
 appContent.setDownloadPercent(cursor.getInt(3));
 appContent.setStatus(AppContent.Status.getByValue(cursor.getInt(4)));
 }
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 if (null != cursor) {
 cursor.close();
 }
 }
 return appContent;
 }
 /**
 *       
 * @param appContent
 */
 public void updateDownloadFile(AppContent appContent) {
 if(appContent == null) {
 return;
 }
 SQLiteDatabase database = getConnection();
 try {
 Log.e(TAG, "update download_file,app name:" + appContent.getName() + ",url:" + appContent.getUrl()
  + ",percent" + appContent.getDownloadPercent() + ",status:" + appContent.getStatus().getValue());
 String sql = "update download_file set app_name=?, url=?, download_percent=?, status=? where url=?";
 Object[] bindArgs = {appContent.getName(), appContent.getUrl(), appContent.getDownloadPercent()
  , appContent.getStatus().getValue(), appContent.getUrl()};
 database.execSQL(sql, bindArgs);
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 }
 }
 /**
 *           
 * @return
 */
 public List<AppContent> getAll() {
 SQLiteDatabase database = getConnection();
 List<AppContent> list = new ArrayList<AppContent>();
 Cursor cursor = null;
 try {
 String sql = "select * from download_file";
 cursor = database.rawQuery(sql, null);
 while (cursor.moveToNext()) {
 AppContent appContent = new AppContent(cursor.getString(1), cursor.getString(2));
 appContent.setDownloadPercent(cursor.getInt(3));
 appContent.setStatus(AppContent.Status.getByValue(cursor.getInt(4)));
 list.add(appContent);
 }
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 if (null != cursor) {
 cursor.close();
 }
 }
 return list;
 }
 /**
 *   url    
 * @param url
 */
 public void delByUrl(String url) {
 if(TextUtils.isEmpty(url)) {
 return;
 }
 SQLiteDatabase database = getConnection();
 try {
 String sql = "delete from download_file where url=?";
 Object[] bindArgs = { url };
 database.execSQL(sql, bindArgs);
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 }
 }
}
5.DownloadInfoDAO,각 스 레 드 가 다운로드 상태 에 대응 하 는 데이터베이스 작업 클래스

package com.bbk.lling.multitaskdownload.db;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import android.util.Log;
import com.bbk.lling.multitaskdownload.beans.DownloadInfo;
import java.util.ArrayList;
import java.util.List;
/**
 * @Class: DownloadInfoDAO
 * @Description:                    
 * @author: lling(www.cnblogs.com/liuling)
 * @Date: 2015/10/13
 */
public class DownloadInfoDAO {
 private static final String TAG = "DownloadInfoDAO";
 private static DownloadInfoDAO dao=null;
 private Context context;
 private DownloadInfoDAO(Context context) {
 this.context=context;
 }
 synchronized public static DownloadInfoDAO getInstance(Context context){
 if(dao==null){
 dao=new DownloadInfoDAO(context);
 }
 return dao;
 }
 /**
 *        
 * @return
 */
 public SQLiteDatabase getConnection() {
 SQLiteDatabase sqliteDatabase = null;
 try {
 sqliteDatabase= new DBHelper(context).getReadableDatabase();
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 }
 return sqliteDatabase;
 }
 /**
 *     
 * @param downloadInfo
 */
 public void insertDownloadInfo(DownloadInfo downloadInfo) {
 if(downloadInfo == null) {
 return;
 }
 //        ,    
 if(getDownloadInfoByTaskIdAndUrl(downloadInfo.getTaskId(), downloadInfo.getUrl()) != null) {
 updateDownloadInfo(downloadInfo);
 return;
 }
 SQLiteDatabase database = getConnection();
 try {
 String sql = "insert into download_info(task_id, download_length, url, is_success) values (?,?,?,?)";
 Object[] bindArgs = { downloadInfo.getTaskId(), downloadInfo.getDownloadLength(),
  downloadInfo.getUrl(), downloadInfo.isDownloadSuccess()};
 database.execSQL(sql, bindArgs);
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 }
 }
 public List<DownloadInfo> getDownloadInfosByUrl(String url) {
 if(TextUtils.isEmpty(url)) {
 return null;
 }
 SQLiteDatabase database = getConnection();
 List<DownloadInfo> list = new ArrayList<DownloadInfo>();
 Cursor cursor = null;
 try {
 String sql = "select * from download_info where url=?";
 cursor = database.rawQuery(sql, new String[] { url });
 while (cursor.moveToNext()) {
 DownloadInfo info = new DownloadInfo();
 info.setTaskId(cursor.getInt(1));
 info.setDownloadLength(cursor.getLong(2));
 info.setDownloadSuccess(cursor.getInt(4));
 info.setUrl(cursor.getString(3));
 list.add(info);
 }
 } catch (Exception e) {
 e.printStackTrace();
 } finally {
 if (null != database) {
 database.close();
 }
 if (null != cursor) {
 cursor.close();
 }
 }
 return list;
 }
 /**
 *   taskid url      
 * @param taskId
 * @param url
 * @return
 */
 public DownloadInfo getDownloadInfoByTaskIdAndUrl(int taskId, String url) {
 if(TextUtils.isEmpty(url)) {
 return null;
 }
 SQLiteDatabase database = getConnection();
 DownloadInfo info = null;
 Cursor cursor = null;
 try {
 String sql = "select * from download_info where url=? and task_id=?";
 cursor = database.rawQuery(sql, new String[] { url, String.valueOf(taskId) });
 if (cursor.moveToNext()) {
 info = new DownloadInfo();
 info.setTaskId(cursor.getInt(1));
 info.setDownloadLength(cursor.getLong(2));
 info.setDownloadSuccess(cursor.getInt(4));
 info.setUrl(cursor.getString(3));
 }
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 if (null != cursor) {
 cursor.close();
 }
 }
 return info;
 }
 /**
 *       
 * @param downloadInfo
 */
 public void updateDownloadInfo(DownloadInfo downloadInfo) {
 if(downloadInfo == null) {
 return;
 }
 SQLiteDatabase database = getConnection();
 try {
 String sql = "update download_info set download_length=?, is_success=? where task_id=? and url=?";
 Object[] bindArgs = { downloadInfo.getDownloadLength(), downloadInfo.isDownloadSuccess(),
  downloadInfo.getTaskId(), downloadInfo.getUrl() };
 database.execSQL(sql, bindArgs);
 } catch (Exception e) {
 Log.e(TAG, e.getMessage());
 } finally {
 if (null != database) {
 database.close();
 }
 }
 }
}
구체 적 인 인터페이스 와 사용 코드 는 코드 를 붙 이지 않 겠 습 니 다.코드 가 좀 많 습 니 다.필요 한 건 데모 소스 를 다운로드 해 보 세 요.
아직 시간 이 많이 걸 리 지 않 았 기 때문에 안에 버그 가 있 을 수 밖 에 없습니다.만약 에 여러분 이 어떤 문 제 를 발견 하면 댓 글 을 남 겨 서 토론 하 는 것 을 환영 합 니 다.감사합니다!  
원본 다운로드:AsyncTask 정지점 전송 실현

좋은 웹페이지 즐겨찾기