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();//通知下载取消事件 }