android后台下载服务的完成及事项
android后台下载功能的完成
首先是基本框架的搭建,用到的是okhttp3已经注入框架butterknife,所以在build.gradle里面添加
compile ‘com.jakewharton:butterknife:7.0.1’
compile ‘com.squareup.okhttp3:okhttp:3.4.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);才行。
更多相关文章
- android开发学习笔记(一)分别通过GET和POST请求从服务器端获取数
- Mac系统下Android(安卓)SDK更新以及ADT无法在线下载
- (4.1.18.4)Android(安卓)Service 服务(三)—— bindService与remot
- Android通知栏颜色改变方法
- Android中无法访问本地Apache服务器原因
- Android(安卓)Studio 安装完成不能打开的方法
- ubuntu 下载配置 android 开发环境 [ jdk 配置 ]
- MAC 安装Eclipse: Failed to get the required ADT version numb
- Android(安卓)网络下载文件 图片 httpurl