最近在复习服务,想想还是写个综合的点的案例来实现。<文件下载>
分析:
异步下载AsyncTask
后台服务开启下载
使用Activity显示界面
开撸
写一个接口,记录下载的状态。
public interface DownloadListener {
/**下载进度*/
void onProgress(int progress);
/**下载成功*/
void onSuccess();
/**下载失败 */
void onFailed();
/**下载暂停 */
void onPaused();
/**下载取消 */
void onCanceled();
}
开启异步线程AsyncTask下载文件
AsyncTask,泛型参数,需要URL,String字符串,来下载文件;在下载过程中需要显示在界面进度,这个进度使用Integer类型;下载完毕之后,也需要一个状态来记录,这个状态也使用Integer来表示。
public class DownloadTask extends AsyncTask<String,Integer,Integer> {
// 定义四个int类型值,来记录文件下载的状态。
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 boolean isCanceled = false;
private boolean isPaused = false;
private int lastProgress;
private DownloadListener downloadListener;
public DownloadTask(DownloadListener mDownloadListener){
this.downloadListener = mDownloadListener;
}
/**
* 任务开始执行该方法,可以做界面的初始化操作。
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 开始执行后台任务,该方法中的所有代码都在自线程中操作。
* */
@Override
protected Integer doInBackground(String... params) {
InputStream is = null; //从服务区读取数据
RandomAccessFile savedFile = null ;
File file = null;
try{
long downloadedLength = 0; // 记录已下载的文件长度
String downloadUrl = params[0];
String fileName =
downloadUrl.substring(downloadUrl.lastIndexOf("/")); //获取文件的名称
// 通过SD卡,获取内部存储的路径
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 = 0;
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 (IOException e) {
e.printStackTrace();
}
}
return TYPE_FAILED;
}
/**
* 获取下载文件的长度
* */
private long getContentLength(String downloadUrl) throws IOException {
OkHttpClient clinent = new OkHttpClient();
Request request = new Request.Builder()
.url(downloadUrl)
.build();
Response response = clinent.newCall(request).execute();
if (response != null && response.isSuccessful()) {
long contentLength = response.body().contentLength();
response.close();
return contentLength;
}
return 0;
}
/**
* 任务执行过程中,要更新UI,通过调用publishProgress()方法执行该方法、
* */
@Override
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
if (progress > lastProgress) {
downloadListener.onProgress(progress);
lastProgress = progress;
}
}
/**
* 任务执行完毕 执行该方法,可以做关闭进度条的操作。
* */
@Override
protected void onPostExecute(Integer integer) {
switch (integer) {
case TYPE_SUCCESS:
downloadListener.onSuccess();
break;
case TYPE_FAILED:
downloadListener.onFailed();
break;
case TYPE_CANCELED:
downloadListener.onCanceled();
break;
case TYPE_PAUSED:
downloadListener.onPaused();
break;
}
}
public void pauseDownload(){
isPaused = true;
}
public void cancelDownload(){
isCanceled = true;
}}}
开启服务下载文件
public class DownloadService extends Service {
private DownloadTask downloadtask;
private DownloadListener listener = new DownloadListener() {
@Override
public void onProgress(int progress) {
// 显示progress 进度
getNotificationManager().notify(1,getNotification("DOWNLOAD...",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_FAILED",-1));
Toast.makeText(DownloadService.this,"下载失败",Toast.LENGTH_SHORT).show();
Log.e("----onFailed------","下载失败了~~~~");
stopForeground(true);
}
@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();
Log.e("~~~~~~~~~~··","onCanceled");
}
};
private String downloadUrl ;
private DownloadBinder mBinder = new DownloadBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class DownloadBinder extends Binder{
/**
* 开始下载
* */
public void startDownload(String url) {
if (downloadtask == null) {
downloadUrl = url;
downloadtask = new DownloadTask(listener);
downloadtask.execute(downloadUrl); //执行异步加载
startForeground(1,getNotification("Download",0)); //开启前台服务;
Toast.makeText(DownloadService.this,"开始下载啦",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 directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
File file = new File(directory+fileName);
if (file . exists()) {
file.delete();
}
getNotificationManager().cancel(1); //关闭通知
}
}
Log.e("---cancelDownload-","取消~~~~");
}
}
private NotificationManager getNotificationManager(){
return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
// 显示对话框;
private Notification getNotification(String title, int progress) {
Intent intent = new Intent(DownloadService.this,MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(DownloadService.this,0,intent,0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle(title);
if (progress > 0) {
builder.setContentText(progress+"%");
builder.setProgress(100,progress,false);
}
builder.setContentIntent(pi);
return builder.build();
}
}
Activity显示下载进度
public class DownloadActivity extends AppCompatActivity implements View.OnClickListener{
private String tag = "DownloadActivity";
private DownloadService.DownloadBinder binder;
private ServiceConnection connection = new ServiceConnection() {
@Override // 服务连接
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (DownloadService.DownloadBinder) service;
}
@Override //服务断开连接
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_download);
initService();
initView();
}
private void initService() {
Intent intent = new Intent(DownloadActivity.this, DownloadService.class);
startService(intent); // 开启服务
bindService(intent,connection,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);
}
}
@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;
}
}
private void initView() {
findViewById(R.id.button_start).setOnClickListener(this);
findViewById(R.id.button_stop).setOnClickListener(this);
findViewById(R.id.button_canceled).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (binder == null) {
Log.e(tag,"------binder==null-------");
return;
}
switch (v.getId()) {
case R.id.button_start:
String url = "https://raw.githubusercontent.com/goulindev/eclipse/master/eclipse-inst-win64.exe";
binder.startDownload(url);
break;
case R.id.button_stop:
binder.pauseDownload();
break;
case R.id.button_canceled:
binder.cancelDownload();
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
stopService(new Intent(this,DownloadService.class));
}
}