摘自于第一行代码
1.定义一个回调接口,用于下载过程中各种状态的的监听和回调
void onProgress(int progress); void onSuccess(); void onFailed(); void onPaused(); void onCanceled();
2.为了更方便在子线程中对UI进行操作,使用AsyncTask
在doInBackground方法中,取出下载的URL地址,然后指定下载到SD卡的Download目录,若存在文件,则读取已下载的字节数,然后用getContentLength方法来验证下载文件的总长度,0则有问题,长度等于已下载文件长度,说明文件下载完成。
用OkHttp发送网络请求,添加一个header,用于告知服务器从哪个字节开始下载
接下来读取服务器响应的数据,使用java流程。
判断用户有无暂定,取消的操作,然后调用publishProgress方法进行通知
OkHttpClient client=new OkHttpClient(); Request request=new Request.Builder() .addHeader("Ranger","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; 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 (IOException e) { e.printStackTrace(); }finally { try { if (is!=null){ is.close(); } if (savedFile!=null){ savedFile.close(); } if (isCanceled&&file!=null){ file.delete(); } }catch (Exception e){ e.printStackTrace(); } } return TYPE_FAILED;
3.建立下载服务,并用NotificationManager的notify方法触发这个通知
4.在MainAc中绑定service
代码如下
downloadService
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.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("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; stopForeground(true); Toast.makeText(DownloadService.this,"Paused",Toast.LENGTH_SHORT).show(); } @Override public void onCanceled() { downloadTask=null; stopForeground(true); Toast.makeText(DownloadService.this,"Download Canceled",Toast.LENGTH_SHORT).show(); } }; private DownloadBinder mBinder=new DownloadBinder(); 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.execute(downloadUrl); startForeground(1,getNotification("Download....",0)); Toast.makeText(DownloadService.this,"Download.....",Toast.LENGTH_SHORT).show(); } } public void pauseDownload(){ if (downloadTask!=null){ downloadTask.pauseDownload(); } } public void cancelDownload(){ if (downloadTask!=null){ downloadTask.cancelDownload(); }else { //取消下载时许将文件删除,并将通知关闭 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 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.setContentTitle(progress+"%"); builder.setProgress(100,progress,false); } return builder.build(); } private NotificationManager getNotificationManager() { return (NotificationManager) getSystemService(NOTIFICATION_SERVICE); } }
DownTask
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 YRC on 2017/2/21. */ public class DownloadTask extends AsyncTask{ 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 listener; private boolean isCanceled=false; private boolean isPaused=false; private int lastprogress; public DownloadTask(DownloadListener listener){ this.listener=listener; } @Override protected Integer doInBackground(String... strings) { InputStream is =null; RandomAccessFile savedFile=null; File file=null; try{ long downloadedLength=0; //记录已下载的文件长度 String downloadUrl=strings[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("Ranger","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; 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 (IOException e) { e.printStackTrace(); }finally { try { if (is!=null){ is.close(); } if (savedFile!=null){ savedFile.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; } }
MainAc
import android.Manifest; 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; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private DownloadService.DownloadBinder downloadBinder; private ServiceConnection connection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { downloadBinder= (DownloadService.DownloadBinder) iBinder; } @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(MainActivity.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="http://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,"拒绝权限将无法使用程序",Toast.LENGTH_SHORT).show(); finish(); } break; default: } } @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); } }
DownloadListener
public interface DownloadListener { void onProgress(int progress); void onSuccess(); void onFailed(); void onPaused(); void onCanceled(); }