android后台下载功能的完成

首先是基本框架的搭建,用到的是okhttp3已经注入框架butterknife,所以在build.gradle里面添加
compile ‘com.jakewharton:butterknife:7.0.1’
compile ‘com.squareup.okhttp3:okhttp:3.4.1’
两个依赖包。

  1. 第一步:定义一个回调接口
  public interface DownloadListener {    void onProgress(int progress);`//`通知当前进度    void onSuccess();    void onFailed();    void onPaused();    void onCanceled();}

2:使用继承AsyncTask来处理异步消息,注意指定三个泛型参数
.Params:执行AsyncTask时需要传入的参数,在后台任务中使用。
.Progress : 需要显示进度的时候用这里指定的泛型作单位。
.Result : 用这里指定的泛型作为结果的返回值。

public class DownloadTask extends AsyncTask {   //定义四个下载状态常量    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 downloadListener;    private boolean isCanceled = false;    private boolean isPaused = false;    private int lastProgress;    public DownloadTask(DownloadListener Listener) {        this.downloadListener = Listener;    }   //后台执行具体的下载逻辑    @Override    protected Integer doInBackground(String... strings) {        InputStream is = null;        RandomAccessFile savedFile = null;        File file = null;        try {            long downloadedLength = 0;//记录下载文件的长度            String downloadUrl = strings[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");                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) {           //回调方法中的onProgress            downloadListener.onProgress(progress);            lastProgress = progress;        }    }    //通知最终的下载结果    //用的listener来回调方法。    @Override    protected void onPostExecute(Integer status) {        switch (status) {            case TYPE_SUCCESS:                downloadListener.onSuccess();                break;            case TYPE_FAILED:                downloadListener.onFailed();                break;            case TYPE_PAUSED:                downloadListener.onPaused();                break;            case TYPE_CANCELED:                downloadListener.onCanceled();                break;            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;    }}

-3.:写服务DownloadService 继承Service
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, "下载成功.在binder里面回调方法里面", 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, "这里只取消不删除", Toast.LENGTH_SHORT).show();        }    };    private DownloadBinder mBinder = new DownloadBinder();    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }   //为了让服务和活动之间联系通信,创建Binder   //提供三个,开始,暂停,取消的方法    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...开始下载binder里面", Toast.LENGTH_SHORT).show();            }        }        public void pauseDowload(){            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, "这里取消下载也删除了", Toast.LENGTH_SHORT).show();                }            }        }    }    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);        builder.setPriority(NotificationCompat.PRIORITY_HIGH);//设置通知重要程度,min,low,默认,high,max        if (progress > 0) {            builder.setContentText(progress + "%");            builder.setProgress(100, progress, false);//三个参数,最大进度,当前进度,是否使用模糊进度条        }        return builder.build();    }    private NotificationManager getNotificationManager() {        return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);    }    public DownloadService() {    }}***布局文件就是三个button,分别为开始,暂停,取消。MainActivity中:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

@Bind(R.id.btn_start)
Button btnStart;
@Bind(R.id.btn_pause)
Button btnPause;
@Bind(R.id.btn_cancel)
Button btnCancel;
private DownloadService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
downloadBinder = (DownloadService.DownloadBinder) iBinder;
}

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

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);btnStart.setOnClickListener(this);
btnPause.setOnClickListener(this);
btnCancel.setOnClickListener(this);

    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);    }

}

@Override
public void onClick(View view) {
if(downloadBinder ==null){
return;
}
switch (view.getId()){
case R.id.btn_start:
String url = “https://raw.githubusercontent.com/guolindev/eclipse/master/” +
“eclipse-inst-win64.exe”;
downloadBinder.startDownload(url);
break;
case R.id.btn_pause:
downloadBinder.pauseDowload();
break;
case R.id.btn_cancel:
downloadBinder.cancelDownload();
break;
default:
break;
}
}

进行到这一步,后台的通知绑定活动,也就可以实现功能了。总结:首先,需要申明两个权限: <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

服务也是需要申明的

 <service            android:name=".DownloadService"            android:enabled="true"            android:exported="true"/>

在最后还要记得重写onDestroy()方法,解绑操作,否则会内存泄露。

@Override    protected  void onDestroy(){        super.onDestroy();        unbindService(connection);    }

PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);中这行代码的主要功能是点击通知里面能进入相应的app.然后在 builder.setContentIntent(pi);中完成。

stopSelf(1);这样才能停止一个服务,最好是传入参数id 就是创建服务的id,只要使用 stopSelf(1);方法 就会默认跳到onDestroy方法中。服务一定要记得在onDestroy()方法中解绑服务,在取消按钮上,要构建intent对象,stopService(intent);才行。

更多相关文章

  1. android开发学习笔记(一)分别通过GET和POST请求从服务器端获取数
  2. Mac系统下Android(安卓)SDK更新以及ADT无法在线下载
  3. (4.1.18.4)Android(安卓)Service 服务(三)—— bindService与remot
  4. Android通知栏颜色改变方法
  5. Android中无法访问本地Apache服务器原因
  6. Android(安卓)Studio 安装完成不能打开的方法
  7. ubuntu 下载配置 android 开发环境 [ jdk 配置 ]
  8. MAC 安装Eclipse: Failed to get the required ADT version numb
  9. Android(安卓)网络下载文件 图片 httpurl

随机推荐

  1. 3.4 管理项目 - 创建Android库
  2. Android扫车牌号识别技术SDK
  3. Android 日历开发教程[四]
  4. 【Android系列】—Android世界全景观
  5. android widget 开发实例 : 桌面便签程序
  6. 18、ESC/POS指令集在android设备上使用实
  7. 安卓数据库sqlite增删查改—模拟用户登录
  8. 什么是ANR,如何避免?
  9. Android对Linux内核的改动你知道多少
  10. android SQLite实现本地登录注册功能,SQL