先定义一个回调接口,用户对下载过程中各种状态进行监听和回调
public interface DownloadListener { void onProgress(int progress); void onSuccess(); void onFailed(); void onPaused(); void onCanceled(); }
新建一个DownloadTask继承自AsyncTask
import android.os.AsyncTask; import android.os.Environment; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public 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; } 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("/")); 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; 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(Exception e){ e.printStackTrace(); } } return TYPE_FAILED; } protected void onProgressUpdate(Integer...values){ int progress=values[0]; if(progress>lastProgress){ listener.onProgress(progress); lastProgress=progress; } } protected void onPostExecute(Integer status){ switch (status){ 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.body().close(); return contentLength; } return 0; } } 这样就将具体的下载功能完成,为了保证DownloadTask可以一直在后台运行,需要创建一个下载的服务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() { 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; Toast.makeText(DownloadService.this,"paused",Toast.LENGTH_SHORT).show(); } @Override public void onCanceled() { downloadTask=null; stopForeground(true); Toast.makeText(DownloadService.this,"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("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 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 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(); } } 修改activity_main.xml中代码<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/start" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start"/> <Button android:id="@+id/pause" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="pause"/> <Button android:id="@+id/cancel" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="cancel"/> </LinearLayout> 最后修改MainActivity中的代码 import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.os.IBinder; 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); Button pauseDownload= (Button) findViewById(R.id.pause); Button cancelDownload= (Button) findViewById(R.id.cancel); startDownload.setOnClickListener(this); pauseDownload.setOnClickListener(this); cancelDownload.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: String url="http://dl.static.iqiyi.com/hz/IQIYIsetup_z22.exe"; downloadBinder.startDownload(url); break; case R.id.pause: downloadBinder.pauseDownload(); break; case R.id.cancel: downloadBinder.cancelDownload(); break; default: break; } } public void onRequestPermissionsResult(int requestCode,String[]permissions,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: } } protected void onDestroy(){ super.onDestroy(); unbindService(connection); } }