使用AsyncTask下载+Service+通知连Notification(控制下载暂停或取消)

来源:互联网 发布:lbp算法matlab 编辑:程序博客网 时间:2024/05/17 02:34

通过阅读郭霖《第一行代码》第二版 服务最佳实践启发,写的小案例


实现通知栏显示下载进度,两个按钮:暂停下载,取消下载(删除下载文件)。


首先在创建工程之后,写一个接口inControllerDownLoad用来回调暂停,取消,ProgressBar进度,下载成功,下载失败,如下:

public interface inControllerDownLoad {    public void onProgress(int progress);    public void onCancle();    public void onPaused();    public void onSuccess();    public void onFailed();}

接着需要写一个线程用来实现文件下载,我们继承AsysncTask命名为DownLoadAsysncTask

代码里叙述AsysncTask使用,上代码:

package com.huida.notificationdemo;import android.content.Context;import android.content.Intent;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 Json on 2017/9/19. *//** * 继承AsyncTask发现有三个泛型参数 * 第一个String表示在执行此线程时候需要传入一个字符串参数 * 第二参数Integer表示用整型数据来作为进度显示单位 * 第三个参数Integer表示使用整型数据来反馈执行结果 */public class DownLoadAsysncTask extends AsyncTask<String, Integer, Integer> {    private final inControllerDownLoad inController;    public static final int SUCCESS = 0;    public static final int FAILED = 1;    public static final int PAUSED = 2;    public static final int CANCELED = 3;    private final Context context;    private boolean isCancled = false;    private boolean isPaused = false;    private int lastProgress;    private String downloadUrl;    private File file;    private RandomAccessFile savedFile;    public DownLoadAsysncTask(inControllerDownLoad inter, Context context) {        this.context = context;        this.inController = inter;    }    /**     * 线程在此方法中执行 downLoadAsysncTask.execute("http://mpge.5nd.com/2016/2016-11-15/74847/1.mp3");这里开启线程     * 参数可以为多个,这里只写了一个参数     *     * @param strings     * @return     */    @Override    protected Integer doInBackground(String... strings) {        InputStream is = null;        long downloadLength = 0;//记录已经下载文件长度        downloadUrl = strings[0];//通过第一个参数拿到下载链接        String fileName = Environment.getExternalStoragePublicDirectory                (Environment.DIRECTORY_DOWNLOADS).getPath() + "测试下载";        file = new File(fileName);        if (file != null) {            downloadLength = file.length();//获取文件所下载的字节长度        }        long countLength = 0;        try {            countLength = getContentLength(downloadUrl);//获取需要下载文件的总长度            if (downloadLength == countLength) {                return SUCCESS;//如果一直 那么下载成功            }            if (countLength == 0) {                return FAILED;//如果总长为0 表示请求失败            }            //这里用到Okhttp 需要在app下的build.gradle 添加依赖 compile 'com.squareup.okhttp3:okhttp:3.8.1'             Response response = new OkHttpClient().newCall(new Request.Builder()                    .addHeader("RANGE", "bytes=" + file.length() + "-").url(downloadUrl).build())                    .execute();            //"RANGE","bytes=" + file.length() + "-",表示从服务器请求file.length() 之后数据,注意格式bytes后有等于号            if (response.body() != null) {                //获取到file.length()字节之后的流                is = response.body().byteStream();                //通过RandomAccessFile写入                savedFile = new RandomAccessFile(file, "rw");                //将指针指向file.length()                savedFile.seek(file.length());                byte[] buff = new byte[1024];                int len;                while ((len = is.read(buff)) != -1) {                    //在下载向文件中写数据时候,如果用户调用了pausedDownLoad(),和cancelDownLoad()方法会监听到此                    //isCancled,isPaused会改变值 以下进行判断                    if (isCancled) {                        return CANCELED;                    } else if (isPaused) {                        return PAUSED;                    } else {                        if (file.length() >= countLength) {                            break;                        }                        savedFile.write(buff, 0, len);                        int progress = (int) ((file.length()) * 100 / countLength);                        publishProgress(progress);//AsyscTask的方法表示更新Progress会调用下方onProgressUpdate()方法                    }                }                response.body().close();                //到此表示流正常写入 返回成功                return SUCCESS;            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                if (is != null) {                    is.close();                }                if (savedFile != null) {                    savedFile.close();                }                if (isCancled && file != null) {                    file.delete();                }            } catch (Exception e) {                e.printStackTrace();            }        }        return FAILED;    }    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.body() != null && response.isSuccessful()) {            response.body().close();            return response.body().contentLength();        }        return 0;    }    /**     * 表示在线程执行前的准备工作     */    @Override    protected void onPreExecute() {        super.onPreExecute();    }    /**     * 这里线程执行完成之后调用,此方法中会在主线程执行     * 判断 线程执行完的返回值,AsyncTask<String, Integer, Integer>第三个参数对应,     * 也是doInBackground(String... strings) 的返回值     *     * @param integer     */    @Override    protected void onPostExecute(Integer integer) {        switch (integer) {            case SUCCESS:                inController.onSuccess();                break;            case CANCELED:                inController.onCancle();                //取消之后接着删除该文件 只有在下载过程中能监听到                if (file != null) {                    file.delete();                }                isCancled = false;                break;            case PAUSED:                inController.onPaused();                break;            case FAILED:                inController.onFailed();                break;        }    }    /**     * 表示更新操作 也是在主线程中执行     *     * @param values 可以为多个 我们在上方 publishProgress(progress);只传入一个     */    @Override    protected void onProgressUpdate(Integer... values) {        int progress = values[0];        if (progress > lastProgress) {            //这里回调接口的更新操作            inController.onProgress(progress);            lastProgress = progress;        }    }    /**     * 暴露次方法用来暂停或继续下载     *     * @param isPaused true表示暂停,false表示继续下载     */    public void pausedDownLoad(boolean isPaused) {        this.isPaused = isPaused;        if (!isPaused) {            Intent intent = new Intent(context, DownLoadService.class);            intent.putExtra("status", "begin");            context.startService(intent);        }    }    /**     * 暴露此方法用来取消下载(会删除该下载文件)     */    public void cancelDownLoad() {        isCancled = true;    }}

线程已经准备好了,这里我们打算在服务中开启此线程,我们写一个服务

DownLoadService 代码里都有注释
ackage com.huida.notificationdemo;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.SystemClock;import android.support.annotation.Nullable;import android.support.v4.app.NotificationCompat;import android.widget.RemoteViews;import android.widget.Toast;import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;/** * Created by Json on 2017/9/19. */public class DownLoadService extends Service {    private static boolean isPause = true;//用来判断暂停还是继续下载    private DownLoadAsysncTask downLoadAsysncTask;    //实现该接口  实现的方法会在downLoadAsysncTask进行回调    private inControllerDownLoad inControllerDownLoad = new inControllerDownLoad() {        @Override        public void onProgress(int progress) {            /**             * getNotificationManager().notify();开启通知栏             * 两个参数             * int id:给我们的Notification 设置id 唯一标识             * Notification:需要我们写的通知栏             */            getNotificationManager().notify(1, getNotification("Downloading...", progress));        }        @Override        public void onCancle() {            stopForeground(true);//取消 通知关闭            getNotificationManager().notify(1, getNotification("取消", -1));            getNotificationManager().cancel(1);            downLoadAsysncTask=null;        }        @Override        public void onPaused() {            getNotificationManager().notify(1, getNotification("暂停", -1));            Toast.makeText(DownLoadService.this, "暂停", Toast.LENGTH_SHORT).show();        }        @Override        public void onSuccess() {            getNotificationManager().notify(1, getNotification("下载完成", -1));            Toast.makeText(DownLoadService.this, "DownLoadSuccess", Toast.LENGTH_SHORT).show();            stopForeground(true);//下载成功 通知关闭            getNotificationManager().cancel(1);            downLoadAsysncTask=null;        }        @Override        public void onFailed() {            stopForeground(false);            getNotificationManager().notify(1, getNotification("下载失败", -1));            Toast.makeText(DownLoadService.this, "DownLoadFailed", Toast.LENGTH_SHORT).show();        }    };    /**     *     * @param s 通知栏显示的数据     * @param progress 通知栏上progress的进度     * @return     */    private Notification getNotification(String s, int progress) {        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);        //使用RemoteViews进行自定义通知栏        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.download_contllor);        //暂停按钮的点击事件        Intent pauseIntent = new Intent(this, DownLoadService.class);        pauseIntent.putExtra("status", "pause");        /*PendingIntent 相当于Inteng进行封装了一层 这个通过getService()得到,         也可以通过getBroadcast(),与我们需要的意图Intent第二参数类型相对应         参数1 上下文         参数2 int requestCode 该PendingIntent的唯一标识,不能重复,否则会判定为同一个PendingIntent 用户自己定义         参数3 PendingIntent.FLAG_UPDATE_CURRENT 表示 通过requestCode 判断是否有该PendingIntent 如果有进行更新        */        PendingIntent pausePendingIntent = PendingIntent.getService(this, 1, pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT);        //给RemoteViews设置点击事件 表示子控件的点击事件        remoteViews.setOnClickPendingIntent(R.id.bt_pause, pausePendingIntent);        //取消按钮的点击事件        Intent goneIntent = new Intent(this, DownLoadService.class);        goneIntent.putExtra("status", "gone");        PendingIntent canclePendingIntent = PendingIntent.getService(this, 0, goneIntent, FLAG_UPDATE_CURRENT);        remoteViews.setOnClickPendingIntent(R.id.bt_cancle, canclePendingIntent);        //此通知的点击事件 随意跳转了 到MainActivity中        Intent goMainActivity=new Intent(this,MainActivity.class);        remoteViews.setOnClickPendingIntent(R.id.remoteView                ,PendingIntent.getActivity(this, 2, goMainActivity, FLAG_UPDATE_CURRENT));        builder.setContent(remoteViews);        remoteViews.setProgressBar(R.id.seek, 100, progress, false);        remoteViews.setTextViewText(R.id.tv, s);        builder.setSmallIcon(R.mipmap.ic_launcher);        builder.setWhen(SystemClock.currentThreadTimeMillis());        return builder.build();    }    /**     * 获取到系统NotificationManager     * @return     */    private NotificationManager getNotificationManager() {        return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);    }    @Nullable    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        String status = intent.getStringExtra("status");        switch (status) {            case "begin":                startDownLoad();                break;            case "gone":                if (downLoadAsysncTask != null) {                    downLoadAsysncTask.cancelDownLoad();                }                break;            case "pause":                if (downLoadAsysncTask != null) {                    downLoadAsysncTask.pausedDownLoad(isPause);                    isPause = !isPause;                }                break;        }        return super.onStartCommand(intent, flags, startId);    }    /**     * 开启DownLoadAsysncTask传入我们实现的接口 和上下文     */    private void startDownLoad() {        downLoadAsysncTask = new DownLoadAsysncTask(inControllerDownLoad, this);        downLoadAsysncTask.execute("http://mpge.5nd.com/2016/2016-11-15/74847/1.mp3");    }}

此时基本完事 别忘了去AndroidManifest.xml将服务注册,在
MainActivity直接调用开启服务
package com.huida.notificationdemo;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //进来我直接调用服务进行开启下载线程       findViewById(R.id.bt_start_download).setOnClickListener(new View.OnClickListener() {           @Override           public void onClick(View view) {               Intent intent = new Intent(MainActivity.this, DownLoadService.class);               intent.putExtra("status","begin");               startService(intent);           }       });    }}


基本一个简单的通知栏下载进度完成

思路可以学习一下,我也是自行写的demo可能还有很多不完善的地方大家见谅




阅读全文
0 0