天天看點

多線程下載下傳,斷點下載下傳

package com.example.lenovo.duoxianchengduandixiazai;

import android.util.Log;

import java.io.BufferedInputStream; import java.io.File; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;

public class DownloadFileUtils {

private final String TAG = "DownloadFileUtils"; private String url;//下載下傳位址 private long fileSize;//下載下傳的檔案大小 private long totalReadSize;//已讀取的檔案大小 private long block;//每條線程下載下傳的長度 private int threadCount;//下載下傳的線程數 private final int threadPoolNum = 5;//線程池的大小 private final int bufferSize = 1024 * 100;//緩沖區大小 private String fileName;//存儲在本地的檔案名稱 private String filePath;//存儲的路徑 private HttpURLConnection urlConnection; private RandomAccessFile randomAccessFile;//根據指定位置寫入資料 private URL uri; private DownloadFileCallback callback;//下載下傳的回調接口 private ExecutorService executorService;//固定大小的線程池 private volatile boolean error = false;//全局變量,使用volatile同步,下載下傳産生異常時改變 public DownloadFileUtils(String url,String filePath,String fileName, int threadCount,DownloadFileCallback callback){ this.url = url; this.filePath = filePath; this.fileName = fileName; this.threadCount = threadCount; this.callback = callback; }

public long getFileSize() { return fileSize; }

public long getTotalReadSize() { return totalReadSize; }

public boolean downloadFile(){ try { uri = new URL(url); urlConnection = (HttpURLConnection) uri.openConnection(); urlConnection.setRequestMethod("GET"); if(urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK){ fileSize = urlConnection.getContentLength();//擷取檔案的長度 block = fileSize / threadCount + 1;//為了避免檔案長度缺失每條線程下載下傳長度增加1 File file = new File(filePath,fileName); if(!file.getParentFile().exists()) file.getParentFile().mkdirs(); executorService = Executors.newFixedThreadPool(threadPoolNum); CountDownLatch countDownLatch = new CountDownLatch(threadCount);//線程計數器 for(int i = 0; i < threadCount; i++){ long startPosition = i * block;//每條線程的開始讀取位置 long endPosition = (i+1) * block - 1;//每條線程的讀取結束位置 randomAccessFile = new RandomAccessFile(file, "rwd"); randomAccessFile.seek(startPosition); executorService.execute(new DownloadThread(i+1, startPosition, endPosition, randomAccessFile,countDownLatch)); } countDownLatch.await();//阻塞線程,直到countDownLatch線程數為零 executorService.shutdown(); callback.downloadSuccess(null);//下載下傳成功時的回調 Log.i(TAG, "下載下傳成功。。。"); return true; } } catch (Exception e) { callback.downloadError(e, "");//下載下傳失敗的回調 e.printStackTrace(); return false; } return false; }

class DownloadThread implements Runnable { private int threadId; private long startPosition; private long endPosition; private RandomAccessFile randomAccessFile; private CountDownLatch countDownLatch;

public DownloadThread(int threadId, long startPosition, long endPosition, RandomAccessFile randomAccessFile, CountDownLatch countDownLatch) { this.threadId = threadId; this.startPosition = startPosition; this.endPosition = endPosition; this.randomAccessFile = randomAccessFile; this.countDownLatch = countDownLatch; }

@Override public void run() { try { HttpURLConnection connection = (HttpURLConnection) uri.openConnection(); connection.setRequestMethod("GET");//以GET方式連接配接 connection.setRequestProperty("Connection", "Keep-Alive");//維持長連接配接 connection.setConnectTimeout(5 * 60 * 1000);//設定連接配接逾時 connection.setAllowUserInteraction(true);//允許使用者互動 connection.setRequestProperty("Range", "bytes="+startPosition+"-"+endPosition);//設定每條線程開始下載下傳的位置 InputStream inputStream = new BufferedInputStream(connection.getInputStream(), bufferSize);//使用緩沖區讀取檔案 byte[] b = new byte[bufferSize]; int len = 0; while(!error && (len = inputStream.read(b)) != -1){ randomAccessFile.write(b,0,len); totalReadSize += len; } if(!error) Log.d(TAG, "線程"+threadId+"下載下傳完成。。。"); else Log.e(TAG, "線程"+threadId+"下載下傳失敗。。。"); inputStream.close(); randomAccessFile.close(); connection.disconnect(); countDownLatch.countDown();//每條線程執行完之後減一 } catch (Exception e) { Log.e(TAG, "線程"+threadId+"下載下傳失敗。。。"); error = true; e.printStackTrace(); callback.downloadError(e, "");//下載下傳失敗的回調 } }

} }

package com.example.lenovo.duoxianchengduandixiazai;

public interface DownloadFileCallback {

void downloadSuccess(Object obj);//下載下傳成功 void downloadError(Exception e,String msg);//下載下傳失敗

}

package com.example.lenovo.duoxianchengduandixiazai;

import android.app.Notification; import android.app.NotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; import android.icu.text.DecimalFormat; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.support.annotation.Nullable; import android.util.Log; import android.widget.RemoteViews;

import java.util.Timer; import java.util.TimerTask;

public class DownloadFileService extends Service {

private DownloadFileUtils downloadFileUtils;//檔案下載下傳工具類 private String filePath;//儲存在本地的路徑 private NotificationManager notificationManager;//狀态欄通知管理類 private Notification notification;//狀态欄通知 private RemoteViews remoteViews;//狀态欄通知顯示的view private final int notificationID = 1;//通知的id private final int updateProgress = 1;//更新狀态欄的下載下傳進度 private final int downloadSuccess = 2;//下載下傳成功 private final int downloadError = 3;//下載下傳失敗 private final String TAG = "DownloadFileService"; private Timer timer;//定時器,用于更新下載下傳進度 private TimerTask task;//定時器執行的任務

@Nullable @Override public IBinder onBind(Intent intent) { return null; }

@Override public void onCreate() { init(); }

private void init() { filePath = Environment.getExternalStorageDirectory() + "/aaa"; notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notification = new Notification(); notification.icon = R.mipmap.ic_launcher;//設定通知消息的圖示 notification.tickerText = "正在下載下傳。。。";//設定通知消息的标題 remoteViews = new RemoteViews(getPackageName(), R.layout.down_notification); remoteViews.setImageViewResource(R.id.IconIV, R.mipmap.ic_launcher); timer = new Timer(); task = new TimerTask() {

@Override public void run() { handler.sendEmptyMessage(updateProgress); } }; }

@Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(new Runnable() {

@Override public void run() { downloadFileUtils = new DownloadFileUtils("http://192.168.2.255/apk/abc.apk", filePath, "abc.apk", 3,callback); downloadFileUtils.downloadFile(); } }).start(); timer.schedule(task, 0, 500); return super.onStartCommand(intent, flags, startId); }

@Override public void onDestroy() { Log.i(TAG, TAG + " is onDestory..."); super.onDestroy(); }

Handler handler = new Handler() {

@Override public void handleMessage(Message msg) { if (msg.what == updateProgress) {//更新下載下傳進度 long fileSize = downloadFileUtils.getFileSize(); long totalReadSize = downloadFileUtils.getTotalReadSize(); if (totalReadSize > 0) { float size = (float) totalReadSize * 100 / (float) fileSize; DecimalFormat format = new DecimalFormat("0.00"); String progress = format.format(size); remoteViews.setTextViewText(R.id.progressTv, "已下載下傳" + progress + "%"); remoteViews.setProgressBar(R.id.progressBar, 100, (int) size, false); notification.contentView = remoteViews; notificationManager.notify(notificationID, notification); } } else if (msg.what == downloadSuccess) {//下載下傳完成 remoteViews.setTextViewText(R.id.progressTv, "下載下傳完成"); remoteViews.setProgressBar(R.id.progressBar, 100, 100, false); notification.contentView = remoteViews; notificationManager.notify(notificationID, notification); if (timer != null && task != null) { timer.cancel(); task.cancel(); } stopService(new Intent(getApplicationContext(), DownloadFileService.class));//stop service } else if (msg.what == downloadError) {//下載下傳失敗 if (timer != null && task != null) { timer.cancel(); task.cancel(); } notificationManager.cancel(notificationID); stopService(new Intent(getApplicationContext(), DownloadFileService.class));//stop service } }

}; DownloadFileCallback callback = new DownloadFileCallback() {

@Override public void downloadSuccess(Object obj) { handler.sendEmptyMessage(downloadSuccess); }

@Override public void downloadError(Exception e, String msg) { handler.sendEmptyMessage(downloadError); } };

}

繼續閱讀