android断点续传多线程下载

来源:互联网 发布:网络教育专科多少费用 编辑:程序博客网 时间:2024/06/06 17:40

活动

public class MainActivity extends AppCompatActivity implements View.OnClickListener{private DownloadService.DownloadBinder downloadBinder;private ServiceConnection connection = new ServiceConnection() {    @Override    public void onServiceDisconnected(ComponentName name) {    }    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        downloadBinder = (DownloadService.DownloadBinder) service;    }};@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    Button startDownload = (Button) findViewById(R.id.start_download);    Button pauseDownload = (Button) findViewById(R.id.pause_download);    Button cancelDownload = (Button) findViewById(R.id.cancel_download);    startDownload.setOnClickListener(this);    pauseDownload.setOnClickListener(this);    cancelDownload.setOnClickListener(this);    Intent intent = new Intent(this, DownloadService.class);    startService(intent); // 启动服务,保证DownloadService在后台运行    bindService(intent, connection, BIND_AUTO_CREATE); // 绑定服务,活动和服务交互    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {        ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);    }//获取SD卡权限}@Overridepublic void onClick(View v) {    if (downloadBinder == null) {        return;    }    switch (v.getId()) {        case R.id.start_download:            String url = "http://192.168.37.23:8080/axis2/xml/get_data.xml";            downloadBinder.startDownload(url);            break;        case R.id.pause_download:            downloadBinder.pauseDownload();            break;        case R.id.cancel_download:            downloadBinder.cancelDownload();            break;        default:            break;    }}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {    switch (requestCode) {        case 1:            if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {                Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();                finish();            }            break;        default:    }}@Overrideprotected void onDestroy() {    super.onDestroy();    unbindService(connection);}}

异步任务

这里我们用到了OkHttp所以要在gradle中添加依赖库:
compile ‘com.squareup.okhttp3:okhttp:3.8.1’

/*第一个参数String表示在执行AsyncTask任务时传入一个字符串参数第二个参数Integer表示使用整型数据来显示下载进度第三个参数Integer表示使用整型数据来执行反馈结果*/public class DownloadTask extends AsyncTask<String, Integer, Integer> {public static final int TYPE_SUCCESS = 0;public static final int TYPE_FAILED = 1;public static final int TYPE_PAUSED = 2;public static final int TYPE_CANCELED = 3;private DownloadListener listener;private boolean isCanceled = false;private boolean isPaused = false;private int lastProgress;//将下载的状态通过DownloadListener进行回调public DownloadTask(DownloadListener listener) {    this.listener = listener;}@Override//后台执行下载的具体逻辑protected Integer doInBackground(String... params) {    InputStream is = null;    RandomAccessFile savedFile = null;//随机读取和写入文件    File file = null;    try {        long downloadedLength = 0; // 记录已下载的文件长度        String downloadUrl = params[0];        String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));        String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();        file = new File(directory + fileName);//下载地址文件名        if (file.exists()) {            downloadedLength = file.length();        }        long contentLength = getContentLength(downloadUrl);        if (contentLength == 0) {            return TYPE_FAILED;        } else if (contentLength == downloadedLength) {            // 已下载字节和文件总字节相等,说明已经下载完成了            return TYPE_SUCCESS;        }        OkHttpClient client = new OkHttpClient();        Request request = new Request.Builder()                // 断点下载,指定从哪个字节开始下载                .addHeader("RANGE", "bytes=" + downloadedLength + "-")                .url(downloadUrl)                .build();        Response response = client.newCall(request).execute();        if (response != null) {            is = response.body().byteStream();            savedFile = new RandomAccessFile(file, "rw");//创建一个随机访问文件流从File参数指定的文件中读取,并可选地写入文件            savedFile.seek(downloadedLength); // 跳过已下载的字节,从文件开头测量的偏移位置,用于设置文件指针。            byte[] b = new byte[1024];            int total = 0;            int len;            while ((len = is.read(b)) != -1) {                if (isCanceled) {                    return TYPE_CANCELED;                } else if (isPaused) {                    return TYPE_PAUSED;                } else {                    total += len;                    savedFile.write(b, 0, len);                    // 计算已下载的百分比                    int progress = (int) ((total + downloadedLength) * 100 / contentLength);                    publishProgress(progress);                }            }            response.body().close();            return TYPE_SUCCESS;        }    } catch (Exception e) {        e.printStackTrace();    } finally {        try {            if (is != null) {                is.close();            }            if (savedFile != null) {                savedFile.close();            }            if (isCanceled && file != null) {                file.delete();            }        } catch (Exception e) {            e.printStackTrace();        }    }    return TYPE_FAILED;}@Override//进度显示protected void onProgressUpdate(Integer... values) {    int progress = values[0];    if (progress > lastProgress) {        listener.onProgress(progress);        lastProgress = progress;    }}@Override//通知下载结果protected void onPostExecute(Integer status) {    switch (status) {        case TYPE_SUCCESS:            listener.onSuccess();            break;        case TYPE_FAILED:            listener.onFailed();            break;        case TYPE_PAUSED:            listener.onPaused();            break;        case TYPE_CANCELED:            listener.onCanceled();        default:            break;    }}public void pauseDownload() {    isPaused = true;}public void cancelDownload() {    isCanceled = true;}//获取下载文件的总长度private long getContentLength(String downloadUrl) throws IOException {    OkHttpClient client = new OkHttpClient();    Request request = new Request.Builder()            .url(downloadUrl)            .build();    Response response = client.newCall(request).execute();    if (response != null && response.isSuccessful()) {        long contentLength = response.body().contentLength();        response.close();        return contentLength;    }    return 0;}}

服务

public class DownloadService extends Service {private DownloadTask downloadTask;private String downloadUrl;private DownloadListener listener = new DownloadListener() {    @Override    public void onProgress(int progress) {        getNotificationManager().notify(1, getNotification("Downloading...", progress));    }    @Override    public void onSuccess() {        downloadTask = null;        // 下载成功时将前台服务通知关闭,并创建一个下载成功的通知        stopForeground(true);        getNotificationManager().notify(1, getNotification("Download Success", -1));        Toast.makeText(DownloadService.this, "Download Success", Toast.LENGTH_SHORT).show();    }    @Override    public void onFailed() {        downloadTask = null;        // 下载失败时将前台服务通知关闭,并创建一个下载失败的通知        stopForeground(true);        getNotificationManager().notify(1, getNotification("Download Failed", -1));        Toast.makeText(DownloadService.this, "Download Failed", Toast.LENGTH_SHORT).show();    }    @Override    public void onPaused() {        downloadTask = null;        Toast.makeText(DownloadService.this, "Paused", Toast.LENGTH_SHORT).show();    }    @Override    public void onCanceled() {        downloadTask = null;        stopForeground(true);        Toast.makeText(DownloadService.this, "Canceled", Toast.LENGTH_SHORT).show();    }};private DownloadBinder mBinder = new DownloadBinder();@Overridepublic IBinder onBind(Intent intent) {    return mBinder;}class DownloadBinder extends Binder {    public void startDownload(String url) {        if (downloadTask == null) {            downloadUrl = url;            downloadTask = new DownloadTask(listener);            downloadTask.execute(downloadUrl);            startForeground(1, getNotification("Downloading...", 0));            Toast.makeText(DownloadService.this, "Downloading...", Toast.LENGTH_SHORT).show();        }    }    public void pauseDownload() {        if (downloadTask != null) {            downloadTask.pauseDownload();        }    }    public void cancelDownload() {        if (downloadTask != null) {            downloadTask.cancelDownload();        } else {            if (downloadUrl != null) {                // 取消下载时需将文件删除,并将通知关闭                String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));                String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();                File file = new File(directory + fileName);                if (file.exists()) {                    file.delete();                }                getNotificationManager().cancel(1);                stopForeground(true);                Toast.makeText(DownloadService.this, "Canceled", Toast.LENGTH_SHORT).show();            }        }    }}private NotificationManager getNotificationManager() {    return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);}private Notification getNotification(String title, int progress) {    Intent intent = new Intent(this, MainActivity.class);    PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);    builder.setSmallIcon(R.mipmap.ic_launcher);    builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));    builder.setContentIntent(pi);    builder.setContentTitle(title);    if (progress >= 0) {        // 当progress大于或等于0时才需显示下载进度        builder.setContentText(progress + "%");        builder.setProgress(100, progress, false);    }    return builder.build();}}