实现下载功能

1.定义一个接口,用于下载过程中各种状态的回调监听。

public interface DownloadListener {
    void onProgress(int progress);
    void onSuccess();
    void onFailed();
    void onPause();
    void onCanceled();
}

 2.接口完成我们写下载程序,并且使它继承AsyncTask<>,泛型方法中第一个为string类型,后两个为Integer类型,作用string 给后台发送字符串数据,第二个作为显示进度,第三个反馈执行结果

我们在这个类中定义4个常量,分别表示下载成功,暂停,下载失败,终止

    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;

 紧接着重写最重要的doInBackground(),onProgressUpdate(),onPostExecte()方法。

我们在doInBackground()方法中获取文件的储存路径,并且判断文件是否存在,如果存在获取文件的大小,我们还用通过下载路径获取需要下载文件的大小,利用getContentLengh()方法获取。

获取后判断获取的值,如果获取的值为0则表示下载文件不存在,如果它和已存在文件大小相等大小证明下载完成

 1   protected Integer doInBackground(String... params) {
 2         RandomAccessFile saveFile = null;
 3         File file=null;
 4         try {
 5             //记录文件长度
 6             long downloadLength = 0;
 7             //获取url
 8             String downloadUrl = params[0];
 9             //获取文件名
10            String fileName= downloadUrl.substring(downloadUrl.lastIndexOf("/"));
11             //指定下载路径
12           String dierctory=  Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
13             //拼接
14             file=new File(dierctory+fileName);
15             //判断文件是否存在如果存在读取文件字节大小
16             if (file.exists()){
17                 downloadLength=file.length();
18             }
19             //通过getContentLength()方法获取需要下载文件大小
20             long contentLength = getContentLength(downloadUrl);
21             if (contentLength==0){
22                 return TYPE_FAILED;
23             }else if (contentLength==downloadLength){
24                 return TYPE_SUCCESS;
25             }

下面我们通过URL的方法发送地址HttpURLConnection我定义为了全局变量

。。。。    
URL url = new URL(downloadUrl);
            connection = (HttpURLConnection)url.openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("RANGE","bytes="+downloadLength+"-");//在已存在文件的基础上继续写入
            in = connection.getInputStream();//得到返回值,这里的返回值是以字节流的形式返回

下面进行判断和关闭流

 if (in!=null){
                saveFile =new RandomAccessFile(file,"rw");
                //跳过已经下载的字节
                saveFile.seek(downloadLength);
                //写入
                byte[] b = new byte[1024];
                int total = 0;
                int len;
                while ((len=in.read(b))!=-1){
                    if (isCanceled){
                        return TYPE_CANCELED;
                    }else if (isPause){
                        return TYPE_PAUSED;
                    }else {
                        total+=len;
                        saveFile.write(b,0,len);
                        //计算一下载的百分比
                        int progress= (int) ((total+downloadLength)*100/contentLength);
                        //以进度条的形式显示
                        publishProgress(progress);
                    }
                }
                //下载完成关闭获取数据流
                in.close();
                return TYPE_SUCCESS;
            }

        }catch (Exception e){

        }finally {
            try {
            //关闭写入流
            if (in!=null){
                    in.close();
                }
                if (saveFile!=null){
                    saveFile.close();
                }
                if (isCanceled && file!=null){
                    file.delete();
                }
            }catch (Exception e){}
        }
        return TYPE_FAILED;
    }

接下来是onProgressUpdate()方法,它的作用是获取得到当前的下载速度有过有变化就调用DownloadListenter的onProgress()方法来通知下载进度更新

    protected void onProgressUpdate(Integer... values) {
        int progress = values[0];
        if (progress>lastProgress){
            listener.onProgress(progress);
            lastProgress=progress;
        }
    }

onPostExecte()方法根据传入的参数回调放发

   protected void onPostExecute(Integer status) {
        switch (status){
            case TYPE_SUCCESS:
                listener.onSuccess();
                break;
            case TYPE_FAILED:
                listener.onFailed();
                break;
            case TYPE_PAUSED:
                listener.onPause();
                break;
            case TYPE_CANCELED:
                listener.onCanceled();
                default:
                break;
        }
    }
    //通知下载更新进度
    public void pauseDownload(){

        isPause =true;
    }
    public void canceDownload(){
        isCanceled = true;
    }
    private long getContentLength(String downloadUri) throws IOException{
        //发送url
        URL url = new URL(downloadUri);
        connection= (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");

        InputStream is = connection.getInputStream();

        //读取返回的文件
        if (is!=null){
            //获取文件大小

            long contentLength=  connection.getContentLength();
            is.close();//关闭请求
            return contentLength;
        }
        return 0;
    }

下载功能写完了就创建一个下载服务并且继承Service.我们在其中创建了DownloadListener的匿名实例

我们先创建一个NotificationManager

    private NotificationManager getNotificationManager(){
        return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    }

 然后用它调用notify()方法去触发这个通知可以当前的下载进度。接下来我们创建Notification实例实现通知,

 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_round);
        builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round));
        //设置点击
        builder.setContentIntent(pi);
        builder.setContentTitle(title);

        if (progress>=0){
            //显示下载进度
            builder.setContentText(progress+"%");
            builder.setProgress(100,progress,false);//false 使进度条显现出来
        }
        return builder.build();
    }

我们创建了匿名实例后它会实现接口中我们定义的那5种方法

    private DownloadListener listener = new DownloadListener() {
        @Override
        public void onProgress(int progress) {
            getNotificationManager().notify(1,getNotification("准备下载",progress));
        }

        @Override
        public void onSuccess() {
            downloadTask =null;
            //关闭前台服务
            stopForeground(true);
            getNotificationManager().notify(1,getNotification("下载成功",-1));
            Toast.makeText(DownloadService.this,"下载成功",Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailed() {
            downloadTask=null;
            stopForeground(true);
            getNotificationManager().notify(1,getNotification("下载失败",-1));
            Toast.makeText(DownloadService.this,"下载失败",Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onPause() {
            downloadTask=null;
            Toast.makeText(DownloadService.this,"下载暂停",Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCanceled() {
            downloadTask=null;
            stopForeground(true);
            Toast.makeText(DownloadService.this,"下载停止",Toast.LENGTH_SHORT).show();
        }
    };

下面我们创建了DownloadBinder,它提供了startDownload(),pauseDownload()和cancelDownload()方法

在startDownload()中我们创建了DownloadTask的实例,将DownloadListener作为参数传入,然后用execute()方法开启下载,在其中我们还调用了stsrtForeground()方法这样就会创建一个持续运行的通知了

    private DownlosdBind mBind = new DownlosdBind();
    public IBinder onBind(Intent intent) {
        return mBind;
    }
    class DownlosdBind 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();
            }
        }

下面我们介绍一下取消,当我们点击取消后删除我们没有下载完的文件

首先判断url是不是存在,如果存在就获取我们所下载文件的位置,然后调用删除方法

   public void cancelDownload(){
            if (downloadTask!=null){
                downloadTask.canceDownload();
            }else {
                if (downloadUrl!=null){
                    //取消下载的时候删除文件
                    String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
                    String dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
                    File file = new File(dir+fileName);
                    if (file.exists()){
                        file.delete();
                    }
                    getNotificationManager().cancel(1);
                    stopForeground(true);
                    Toast.makeText(DownloadService.this,"Canceled 取消",Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

在主函数中首先我们创建ServiceConnection的匿名类,然后在onServiceConnected()方法中的到DownloadBinder实例

    DownloadService.DownlosdBind downlosdBind;
    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downlosdBind = (DownloadService.DownlosdBind) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

在onCreate()方法中通过意图开启活动并且通过bindSrevice()方法绑定服务

   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this,DownloadService.class);
        startService(intent);
        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); } }

在点击按钮中调用对应的方法

  public void click1(View v){
        String url = "http://sw.bos.baidu.com/sw-search-sp/software/b9e8735a86508/huya_audience_1.0.2.0.exe";
        downlosdBind.startDownload(url);
    }
    public void click2(View v){
        downlosdBind.pauseDownload();
    }
    public void click3(View v){
        downlosdBind.cancelDownload();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
原文地址:https://www.cnblogs.com/lyl123/p/7211196.html