《第一行代码Android》学习总结第十章 Service实践——下载功能示例
16lz
2021-01-26
1、在app/build.gradle文件,dependencies闭包中添加依赖。
compile 'com.squareup.okhttp3:okhttp:3.4.1'
2、定义DownloadListener回调接口,用于对下载过程中的状态进行监听和回调。
public interface DownloadListener { void onProgress(int progress); //通知当前下载进度 void onSuccess(); //通知下载成功事件 void onFailed(); //通知下载失败事件 void onPaused(); //通知下载暂停事件 void onCanceled(); //通知下载取消事件}
3、新建DownloadTask继承自AsyncTask。
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 listener; private boolean isCanceled = false; private boolean isPaused = false; private int lastProgress;public DownloadTask(DownloadListener listener) {//下载状态会根据该参数回调 this.listener = listener; }//后台执行下载逻辑 @Override protected Integer doInBackground(String... params) { InputStream is = null; RandomAccessFile saveFile = null; File file = null; try { long downloadedLength = 0; //记录已下载的文件长度 String downloadUrl = params[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(request != null){ is = response.body().byteStream(); saveFile = new RandomAccessFile(file, "rw"); saveFile.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; saveFile.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(saveFile != null){ saveFile.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){ listener.onProgress(progress); lastProgress = progress; } }//通知最终下载结果 @Override protected void onPostExecute(Integer status) { switch (status){ case TYPE_SUCCESS: listener.onSuccess(); break; case TYPE_FAILED: listener.onFailed(); break; case TYPE_PAUSED: listener.onPaused(); break; case TYPE_CANCELED: listener.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.body().close(); return contentLength; } return 0; }}
4、新建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, "Download Success", 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, "Canceled", Toast.LENGTH_SHORT).show(); } }; private DownloadBinder mBinder = new DownloadBinder(); @Override public IBinder onBind(Intent intent) { return mBinder; }//用于活动与服务通信 class DownloadBinder extends Binder{ public void startDownload(String url){ if(downloadTask == null){ downloadUrl = url; downloadTask =new DownloadTask(listener);//执行DownloadTask后台下载 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(); } } public void cancelDownload(){ if(downloadTask != null){ downloadTask.cancelDownload(); } 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, "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, 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); if(progress>0){ builder.setContentText(progress + "%");// setProgress()方法:在通知上设置进度条,参数一传入通知最大进度,参数二传入通知当前进度,参数三表示是否使用模糊进度条 builder.setProgress(100, progress, false); } return builder.build(); }}
5、修改activity_main中代码,添加三个按钮用于开始下载,暂停下载和取消下载。
6、修改MainActivity中代码。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{private DownloadService.DownloadBinder downloadBinder;//匿名类 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) {//获取DownloadService实例,用于活动与服务通信 downloadBinder = (DownloadService.DownloadBinder) service; } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button startDownload = (Button) findViewById(R.id.start_download); Button pauseDownload = (Button) findViewById(R.id.pause_download); Button cancelDownload = (Button) findViewById(R.id.cancel_download); startDownload.setOnClickListener(this); pauseDownload.setOnClickListener(this); cancelDownload.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.start_download: String url = "https://raw.githubusercontent.com/guolindev/eclipse/master/eclipse-inst-win64.exe"; downloadBinder.startDownload(url); break; case R.id.pause_download: downloadBinder.pauseDownload(); break; case R.id.cancel_download: downloadBinder.cancelDownload(); break; default: 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 deny the permission", Toast.LENGTH_SHORT).show(); finish(); } break; default: } } @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); //解绑服务 }}
7、在AndroidManifest中进行权限声明。
更多相关文章
- 解决Android(安卓)SDK Manager下载太慢问题
- AOSP android 源码批量下载 windows平台
- Android(安卓)Volley.jar包下载
- Android判断后台服务是否开启的两种方法实例详解
- Android搭建客户端连接java构建的服务端
- 解决Android(安卓)SDK Manager更新、下载速度慢
- Android软件版本更新
- Android(安卓)Q适配(4)-------针对后台 Activity 启动的限制
- Android(安卓)通知机制 Toast和Notification