1.定义一个接口,用于下载过程中各种状态的回调监听。
public interface DownloadListener { void onProgress(int progress); void onSuccess(); void onFailed(); void onPause(); void onCanceled(); }
2.接口完成我们写下载程序,并且使它继承AsyncTask<>,泛型方法中第一个为string类型,后两个为Integer类型,作用string 给后台发送字符串数据,第二个作为显示进度,第三个反馈执行结果
我们在这个类中定义4个常量,分别表示下载成功,暂停,下载失败,终止
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;
紧接着重写最重要的doInBackground(),onProgressUpdate(),onPostExecte()方法。
我们在doInBackground()方法中获取文件的储存路径,并且判断文件是否存在,如果存在获取文件的大小,我们还用通过下载路径获取需要下载文件的大小,利用getContentLengh()方法获取。
获取后判断获取的值,如果获取的值为0则表示下载文件不存在,如果它和已存在文件大小相等大小证明下载完成
1 protected Integer doInBackground(String... params) { 2 RandomAccessFile saveFile = null; 3 File file=null; 4 try { 5 //记录文件长度 6 long downloadLength = 0; 7 //获取url 8 String downloadUrl = params[0]; 9 //获取文件名 10 String fileName= downloadUrl.substring(downloadUrl.lastIndexOf("/")); 11 //指定下载路径 12 String dierctory= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath(); 13 //拼接 14 file=new File(dierctory+fileName); 15 //判断文件是否存在如果存在读取文件字节大小 16 if (file.exists()){ 17 downloadLength=file.length(); 18 } 19 //通过getContentLength()方法获取需要下载文件大小 20 long contentLength = getContentLength(downloadUrl); 21 if (contentLength==0){ 22 return TYPE_FAILED; 23 }else if (contentLength==downloadLength){ 24 return TYPE_SUCCESS; 25 }
下面我们通过URL的方法发送地址HttpURLConnection我定义为了全局变量
。。。。 URL url = new URL(downloadUrl); connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("RANGE","bytes="+downloadLength+"-");//在已存在文件的基础上继续写入 in = connection.getInputStream();//得到返回值,这里的返回值是以字节流的形式返回
下面进行判断和关闭流
if (in!=null){ saveFile =new RandomAccessFile(file,"rw"); //跳过已经下载的字节 saveFile.seek(downloadLength); //写入 byte[] b = new byte[1024]; int total = 0; int len; while ((len=in.read(b))!=-1){ if (isCanceled){ return TYPE_CANCELED; }else if (isPause){ return TYPE_PAUSED; }else { total+=len; saveFile.write(b,0,len); //计算一下载的百分比 int progress= (int) ((total+downloadLength)*100/contentLength); //以进度条的形式显示 publishProgress(progress); } } //下载完成关闭获取数据流 in.close(); return TYPE_SUCCESS; } }catch (Exception e){ }finally { try { //关闭写入流 if (in!=null){ in.close(); } if (saveFile!=null){ saveFile.close(); } if (isCanceled && file!=null){ file.delete(); } }catch (Exception e){} } return TYPE_FAILED; }
接下来是onProgressUpdate()方法,它的作用是获取得到当前的下载速度有过有变化就调用DownloadListenter的onProgress()方法来通知下载进度更新
protected void onProgressUpdate(Integer... values) { int progress = values[0]; if (progress>lastProgress){ listener.onProgress(progress); lastProgress=progress; } }
onPostExecte()方法根据传入的参数回调放发
protected void onPostExecute(Integer status) { switch (status){ case TYPE_SUCCESS: listener.onSuccess(); break; case TYPE_FAILED: listener.onFailed(); break; case TYPE_PAUSED: listener.onPause(); break; case TYPE_CANCELED: listener.onCanceled(); default: break; } }
//通知下载更新进度 public void pauseDownload(){ isPause =true; } public void canceDownload(){ isCanceled = true; } private long getContentLength(String downloadUri) throws IOException{ //发送url URL url = new URL(downloadUri); connection= (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); InputStream is = connection.getInputStream(); //读取返回的文件 if (is!=null){ //获取文件大小 long contentLength= connection.getContentLength(); is.close();//关闭请求 return contentLength; } return 0; }
下载功能写完了就创建一个下载服务并且继承Service.我们在其中创建了DownloadListener的匿名实例
我们先创建一个NotificationManager
private NotificationManager getNotificationManager(){ return (NotificationManager) getSystemService(NOTIFICATION_SERVICE); }
然后用它调用notify()方法去触发这个通知可以当前的下载进度。接下来我们创建Notification实例实现通知,
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_round); builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round)); //设置点击 builder.setContentIntent(pi); builder.setContentTitle(title); if (progress>=0){ //显示下载进度 builder.setContentText(progress+"%"); builder.setProgress(100,progress,false);//false 使进度条显现出来 } return builder.build(); }
我们创建了匿名实例后它会实现接口中我们定义的那5种方法
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("下载成功",-1)); Toast.makeText(DownloadService.this,"下载成功",Toast.LENGTH_SHORT).show(); } @Override public void onFailed() { downloadTask=null; stopForeground(true); getNotificationManager().notify(1,getNotification("下载失败",-1)); Toast.makeText(DownloadService.this,"下载失败",Toast.LENGTH_SHORT).show(); } @Override public void onPause() { 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(); } };
下面我们创建了DownloadBinder,它提供了startDownload(),pauseDownload()和cancelDownload()方法
在startDownload()中我们创建了DownloadTask的实例,将DownloadListener作为参数传入,然后用execute()方法开启下载,在其中我们还调用了stsrtForeground()方法这样就会创建一个持续运行的通知了
private DownlosdBind mBind = new DownlosdBind(); public IBinder onBind(Intent intent) { return mBind; } class DownlosdBind extends Binder{ public void startDownload(String url){ if (downloadTask==null){ downloadUrl=url; downloadTask = new DownloadTask(listener); 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(); } }
下面我们介绍一下取消,当我们点击取消后删除我们没有下载完的文件
首先判断url是不是存在,如果存在就获取我们所下载文件的位置,然后调用删除方法
public void cancelDownload(){ if (downloadTask!=null){ downloadTask.canceDownload(); }else { if (downloadUrl!=null){ //取消下载的时候删除文件 String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/")); String dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath(); File file = new File(dir+fileName); if (file.exists()){ file.delete(); } getNotificationManager().cancel(1); stopForeground(true); Toast.makeText(DownloadService.this,"Canceled 取消",Toast.LENGTH_SHORT).show(); } } } }
在主函数中首先我们创建ServiceConnection的匿名类,然后在onServiceConnected()方法中的到DownloadBinder实例
DownloadService.DownlosdBind downlosdBind; ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { downlosdBind = (DownloadService.DownlosdBind) service; } @Override public void onServiceDisconnected(ComponentName name) { } };
在onCreate()方法中通过意图开启活动并且通过bindSrevice()方法绑定服务
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); 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); } }
在点击按钮中调用对应的方法
public void click1(View v){ String url = "http://sw.bos.baidu.com/sw-search-sp/software/b9e8735a86508/huya_audience_1.0.2.0.exe"; downlosdBind.startDownload(url); } public void click2(View v){ downlosdBind.pauseDownload(); } public void click3(View v){ downlosdBind.cancelDownload(); } @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); }