Android---服务的最佳实践(完整版的下载实例)
2017-09-08 17:13
281 查看
一、定义回调接口
二、定义下载类
三、定义服务
四、调用
public interface DownloadListener { /* * 接口类,使用回调 */ void onProgress(int progress); void onSuccess(); void onFailed(); void onPaused(); void onCanceled(); }
二、定义下载类
package com.mycompany.servicebestpractice; 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 sstek_mars on 2017/9/8. */ /** * AsyncTask的三个泛型参数 * 第一个参数指定为String,表示在执行AsyncTask的时候需要传入一个字符串参数给后台任务 * 第二个泛型参数指定为Integer,表示使用整数型数据来作为进度显示单位 * 第三个泛型参数指定为Integer,表示使用整型数据来反馈执行结果 */ public abstract class DownloadTask extends AsyncTask<String, Integer, Integer> { 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; } /** * 重写doInBackground() onProgressUpdate() onPostExecute() * doInBackground():用于在后台执行具体的下载逻辑 * onProgressUpdate():用于在界面上更新当前的下载进度 * onPostExecute():用于通知最终的下载结果 */ @Override protected Integer doInBackground(String... params) { InputStream is = null; RandomAccessFile saveFile = null; File file = null; try { long downloadedLength = 0; // 记录下载的文件长度 String dowloadUrl = params[0]; // 从URL中解析出下载的文件名 String fileName = dowloadUrl.substring(dowloadUrl.lastIndexOf("/")); // 将文件下载的指定位置 String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath(); // 判断文件是否存在,已经存在的就无需下载了 file = new File(directory + fileName); if (file.exists()) { // 如果已存在,读取已下载的字节数,用于启动断点下载功能 downloadedLength = file.length(); } long contentLength = getContentLength(dowloadUrl); if (contentLength == 0) { return TYPE_FAILED; }else if(contentLength == downloadedLength){ // 已下载的字节和文件总字节相等,说明已经下载完成了 return TYPE_SUCCESS; } OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() // 添加header用于告诉服务器我们想从哪个字节开始下载,开始断点下载,知道从哪个字节开始下载 .addHeader("RANGE", "bytes=" + downloadedLength + "-") .url(dowloadUrl) .build(); Response response = client.newCall(request).execute(); if (response != null) { // 使用jiava文件流的方式,不断的从网络读取数据,不断的写入本地 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 integer) { switch (integer) { 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.close(); return contentLength; } return 0; } }
三、定义服务
package com.mycompany.servicebestpractice; 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.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.widget.Toast; import java.io.File; 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("下载中。。。", progress)); } @Override public void onSuccess() { downloadTask = null; // 下载成功时将前台的服务通知关闭,并创建一个下载成功的通知 stopForeground(true); getNotificationManager().notify(1, getNotification("Download success", -1)); Toast.makeText(DownloadService.this, "下载成功", Toast.LENGTH_SHORT).show(); } @Override public void onFailed() { downloadTask = null; // 下载失败时将前台的服务通知关闭,并创建一个下载失败的通知 stopForeground(true); getNotificationManager().notify(1, getNotification("Download success", -1)); Toast.makeText(DownloadService.this, "下载失败", Toast.LENGTH_SHORT).show(); } @Override public void onPaused() { downloadTask = null; Toast.makeText(DownloadService.this, "下载暂停", 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(); @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } class DownloadBinder extends Binder { public void startDownload(String url) { if (downloadTask == null) { downloadUrl = url; 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(); } else { if (downloadUrl != null) { // 取消下载是需将文件删除,并将通知关闭 String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/")); String dirdectory = Environment.getExternalStoragePublicDirectory(Environment .DIRECTORY_DOWNLOADS).getPath(); File file = new File(dirdectory + fileName); if (file.exists()) { file.delete(); } getNotificationManager().cancel(1); stopForeground(true); Toast.makeText(DownloadService.this, "取消", 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 + "%"); builder.setProgress(100, progress, false); } return builder.build(); } }
四、调用
package com.mycompany.servicebestpractice; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; 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.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.util.jar.Manifest; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private DownloadService.DownloadBinder downloadBinder; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { downloadBinder = (DownloadService.DownloadBinder) service; } @Override public void onServiceDisconnected(ComponentName name) { } }; @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 cancleDownload = (Button) findViewById(R.id.cancel_download); startDownload.setOnClickListener(this); pauseDownload.setOnClickListener(this); cancleDownload.setOnClickListener(this); Intent intent = new Intent(this, DownloadService.class); startService(intent); // 启动服务 bindService(intent, connection, BIND_AUTO_CREATE); // 绑定服务 if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{ android.Manifest.permission.WRITE_EXTERNAL_STORAGE }, 1); } } @Override public void onClick(View v) { if (downloadBinder == null) { return; } switch (v.getId()) { case R.id.start_download: String url = "https://raw.githubusercontent.com/guolindev/eclipse/master/ec;o[se=inst-win.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, "权限被拒绝无法使用", Toast.LENGTH_SHORT).show(); finish(); } break; default: break; } } @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); } }
相关文章推荐
- Android权限最佳实践和代码实例分析
- 【Android开发】BitMap优化最佳实践及官方Demo“图片墙”实例详解
- Android中(Service )服务的最佳实践——后台执行的定时任务
- Android初级开发(十)——服务—下载实例
- 设计微服务的最佳实践
- Android 屏幕适配最佳实践
- 网络数据请求实践一:android-async-http实现下载和上传
- RESTful服务最佳实践——(十三)
- Android中管理多个Fragment的最佳实践,完美解决保存状态与重影问题 时间 2015-07-23 23:29:00 博客园-原创精华区 原文 http://www.cnblogs.com
- Android UI 设计最佳实践
- 【转载】Android最佳实践之响应灵…
- [Android进阶]Android 开发最佳实践
- Android 开发最佳实践
- Android 开发最佳实践
- Android最佳实践性能(二)性能提示
- Android最佳性能实践——布局优化技巧之<include>、<merge>标签及仅在需要时才加载布局的:ViewStub
- Android 设计的的最佳实践
- [实践] Android5.1.1源码 - 在Framework中添加自定义系统服务
- Android 快速开发系列 ORMLite 框架最佳实践
- 最佳实践之 Android代码规范