《第一行代码》笔记(17)——后台下载案例

package com.zjw.myservice4;

import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

//10.6 p365 服务的最佳实践——完整的下载示例
/*
大概:
1.加上OkHttp的依赖(黄油刀依赖),权限:联网,读取存储卡
2.定义监听接口DownloadListener
3.用AsyncTask来实现下载功能
4.保证AsyncTask可在后台一直运行,创建一个DownloadService服务
5.主布局UI:三个Button,开始,暂停,取消下载
6.主代码
 */

public class PracticeOfService extends AppCompatActivity {

    @BindView(R.id.btn_start_download)
    Button mBtnStartDownload;
    @BindView(R.id.btn_pause_download)
    Button mBtnPauseDownload;
    @BindView(R.id.btn_cancel_download)
    Button mBtnCancelDownload;

    private DownloadService.DownloadBinder mDownloadBinder;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mDownloadBinder = (DownloadService.DownloadBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_practice_of_service);
        ButterKnife.bind(this);

        //开启服务,绑定服务
        Intent intent = new Intent(this, DownloadService.class);
        startService(intent);
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

        //运行时权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }
    }

    //点击事件
    @OnClick({R.id.btn_start_download, R.id.btn_pause_download, R.id.btn_cancel_download})
    public void onViewClicked(View view) {
        if(mDownloadBinder==null){
           return;
        }
        switch (view.getId()) {
            case R.id.btn_start_download:
                String url= "https://raw.githubusercontent.com/guolindev/eclipse/master/eclipse-inst-win64.exe";
                mDownloadBinder.startDownload(url);
                break;
            case R.id.btn_pause_download:
                mDownloadBinder.pauseDownload();
                break;
            case R.id.btn_cancel_download:
                mDownloadBinder.cancelDownload();
                break;
        }
    }

    //申请权限回调
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    //如果用户拒绝请求进行的操作
                    Toast.makeText(this, "You denid the permission,the program will be close", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }

    //解绑
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mServiceConnection);//解绑
    }
}
package com.zjw.myservice4;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.support.v7.app.NotificationCompat;
import android.widget.Toast;

import java.io.File;

public class DownloadService extends Service {
    private DownloadTask mDownloadTask;//后台任务
    private String mDownloadUrl;//下载路径
    //重写监听器的方法
    private DownloadListener mDownloadListener = new DownloadListener() {
        @Override
        public void onProgress(int progress) {
            getNotificationManager().notify(1, getNotification("Downloading...", progress));
        }

        @Override
        public void onSuccess() {
            mDownloadTask = null;
            //下载成功时将前台服务通知关闭,并创建一个下载成功的通知
            stopForeground(true);
            getNotificationManager().notify(1, getNotification("Download Success", -1));
            Toast.makeText(DownloadService.this, "Download Success", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailed() {
            mDownloadTask = null;
            //下载失败时将前台服务通知关闭,并创建一个下载失败的通知
            stopForeground(true);
            getNotificationManager().notify(1, getNotification("Download Failed", -1));
            Toast.makeText(DownloadService.this, "Download Failed", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onPause() {
            mDownloadTask = null;
            Toast.makeText(DownloadService.this, "Paused", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCanceled() {
            mDownloadTask = null;
            stopForeground(true);
            Toast.makeText(DownloadService.this, "Canceled", Toast.LENGTH_SHORT).show();
        }
    };

    private DownloadBinder mDownloadBinder = new DownloadBinder();

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

    class DownloadBinder extends Binder {
        public void startDownload(String url) {
            if (mDownloadTask == null){
                mDownloadUrl=url;
                mDownloadTask=new DownloadTask(mDownloadListener);
                mDownloadTask.execute(mDownloadUrl);
                startForeground(1,getNotification("Downloading...",0));
                Toast.makeText(DownloadService.this, "Downloading...", Toast.LENGTH_SHORT).show();
            }
        }

        public void pauseDownload() {
            if (mDownloadTask != null){
                mDownloadTask.pauseDownload();
            }
        }

        public void cancelDownload() {
            if (mDownloadTask != null){
                mDownloadTask.cancelDownload();
            }else{
                if (mDownloadUrl != null){
                    //取消下载时需要将文件删除,并将通知关闭
                    String fileName = mDownloadUrl.substring(mDownloadUrl.lastIndexOf("/"));//从地址最后的"/"后截取文件名
                    //下载到Environment.DIRECTORY_DOWNLOADS即SD卡的downloads目录
                    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, "Download 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, PracticeOfService.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setContentTitle(title);
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
        builder.setContentIntent(pendingIntent);
        if (progress > 0) {
            //进度大于等于0时才需要显示下载进度
            builder.setContentText(progress + "%");
            builder.setProgress(100, progress, false);//参数:最大进度,当前进度,是否使用模糊进度条
        }
        return builder.build();
    }
}
package com.zjw.myservice4;

import android.os.AsyncTask;
import android.os.Environment;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by hp on 2017/7/27.
 */

/*
<String,Integer,Integer>
1.传入一个字符串给后台任务
2.表示整形数据为进度显示单位
3.整型数据反馈执行结果
 */
public class DownloadTask extends AsyncTask<String, Integer, Integer> {

    //定义下载状态
    private static final int TYPE_SUCCESS = 0;//下载成功
    private static final int TYPE_FAILED = 1;//下载失败
    private static final int TYPE_PAUSED = 2;//下载暂停
    private static final int TYPE_CANCELED = 3;//下载取消

    //监听器
    private DownloadListener mDownloadListener;

    private boolean isCancelled = false;
    private boolean isPaused = false;

    private int lastProcess;

    //构造方法,获取监听器
    public DownloadTask(DownloadListener downloadListener) {
        mDownloadListener = downloadListener;
    }

    @Override
    protected Integer doInBackground(String... params) {
        //在后台执行下载操作
        InputStream inputStream = null;
        RandomAccessFile savedFile = null;
        File file = null;
        try {
            long downloadedLength = 0;//记录下已经下载的文件长度
            String downloadUrl = params[0];//从传入的参数获取下载地址

            String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));//从地址最后的"/"后截取文件名
            //下载到Environment.DIRECTORY_DOWNLOADS即SD卡的downloads目录
            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 (downloadedLength == contentLength) {//如果下载文件大小和已下载文件大小相同,说明已下完
                return TYPE_SUCCESS;
            }

            //网络请求
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request = new Request.Builder()
                    .addHeader("RANGE", "bytes=" + downloadedLength + "-")//告诉服务器要从哪一个字节开始下载
                    .url(downloadUrl)
                    .build();
            Response response = okHttpClient.newCall(request).execute();

            //处理请求结果
            if (response != null) {
                inputStream = response.body().byteStream();
                savedFile = new RandomAccessFile(file, "rw");
                savedFile.seek(downloadedLength);//跳过已下载的字节
                byte[] b = new byte[1024];
                int len;
                int total = 0;
                while ((len = inputStream.read(b)) != -1) {
                    if (isCancelled) {
                        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 (inputStream != null) {
                    inputStream.close();
                }
                if (savedFile != null) {
                    savedFile.close();
                }
                if (isCancelled && (file != null)) {
                    file.delete();
                }
            } catch (Exception e) {
            }
        }
        return TYPE_FAILED;
    }


    @Override
    protected void onProgressUpdate(Integer... values) {
        int process = values[0];
        if (process > lastProcess) {
            mDownloadListener.onProgress(process);
            lastProcess = process;
        }
    }

    @Override
    protected void onPostExecute(Integer status) {
        switch (status) {
            case TYPE_SUCCESS:
                mDownloadListener.onSuccess();
                break;
            case TYPE_FAILED:
                mDownloadListener.onFailed();
                break;
            case TYPE_PAUSED:
                mDownloadListener.onPause();
                break;
            case TYPE_CANCELED:
                mDownloadListener.onCanceled();
                break;
            default:
                break;
        }
    }

    public void pauseDownload() {
        isPaused = true;
    }

    public void cancelDownload() {
        isCancelled = true;
    }

    //获取下载文件的总长度
    private long getContentLength(String downloadUrl) {
        try {
            //网络请求
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(downloadUrl)
                    .build();
            Response response = okHttpClient.newCall(request).execute();
            if (response != null&&response.isSuccessful()) {
                long contentLength=response.body().contentLength();
                response.close();
                return contentLength;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }
}
package com.zjw.myservice4;

/**
 * Created by hp on 2017/7/27.
 */

public interface DownloadListener {
    void onProgress(int progress);//通知当前下载进度
    void onSuccess();//通知下载成功事件
    void onFailed();//通知下载失败事件
    void onPause();//通知下载暂停事件
    void onCanceled();//通知下载取消事件
}

转载于:https://my.oschina.net/u/3620480/blog/1491761

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值