Android---服务的最佳实践(完整版的下载实例)
来源:互联网 发布:淘宝信用等级怎么提升 编辑:程序博客网 时间:2024/06/05 10:37
一、定义回调接口
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); }}
阅读全文
0 0
- Android---服务的最佳实践(完整版的下载实例)
- android优化的最佳实践
- Android Splash 的最佳实践
- Property和实例变量(Ivar)的最佳实践
- 服务实践—下载实例
- Android中(Service )服务的最佳实践——后台执行的定时任务
- 《德川家康》完整版的下载
- Android 设计的的最佳实践
- android学习二十四(网络编程的最佳实践)
- Android后台作业的最佳实践(一)
- 我的android最佳实践-listview
- Android UI自动化测试的最佳实践
- Android UI自动化测试的最佳实践
- 【android】适配多屏幕的最佳实践
- Android登录页面的最佳实践
- Android Translucent System Bar 的最佳实践
- Android中后台任务的最佳实践
- 免费的Scrum 和 XP 最佳实践的电子书下载
- shell脚本入门---$ 相关符号篇
- java 带资源的try语句
- jquery.tmplate模板引擎使用心得
- xrandr设置分辨率
- stop()与subspend()区别 sleep()与wait()的区别
- Android---服务的最佳实践(完整版的下载实例)
- Windows程序设计-鼠标
- PAT 乙级练习题1014. 福尔摩斯的约会 (20)
- Android 7.0 插卡后APN信息的加载流程、UI界面编辑APN的流程及Android中APN配置相关的漏洞
- 扫描二维码
- 常见的状态码
- Android Hanlder-Message-Looper机制
- 笔记:yum/rpm安装的mysql卸载方法
- Unique_Paths