1)新建一个dowmloadfile的项目
2)在app/build中添加Okhttp的依赖
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
compile 'com.squareup.okhttp3:okhttp:3.4.1'//添加依赖
}
3)定义一个回掉接口DownloadListener 用于事件的监听
public interface DownloadListener {
void onProgress(int progress);//通知当前下载进度
void onSuccess();//通知下载成功
void onFiled();//通知下载失败
void onPaused();//下载暂停
void inCanceled();//下载取消
}
4)使用来实现下载
package com.example.dowmloadfile.Myclass;
import android.os.AsyncTask;
import android.os.Environment;
import com.example.dowmloadfile.imp.DownloadListener;
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 海绵宝宝 on 2019/5/13.
*/
/**三个参数第一个为需要传入给后台的数据类型,第二个是进度显示类型,第三个为使用Integer作为反馈结果类型**/
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 downloadListener;
private boolean isCanceled=false;
private boolean isPaused=false;
private int lastProgress;
//通过DownLoadTask回调下载状态
public DownLoadTask(DownloadListener listener){
downloadListener=listener;
}
@Override//后台执行具体的下载逻辑
protected Integer doInBackground(String... params) {
InputStream is=null;
RandomAccessFile savedFile=null;
File file=null;
try{
long downloadLength=0;
String downloadUrl=params[0];
String fileName=downloadUrl.substring(downloadUrl.lastIndexOf("/"));//解析出下载的文件名
String derectory= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();//获取本地的下载文件夹的路径
file=new File(derectory+fileName);
if (file.exists()){
downloadLength=file.length();
}
long contentLength=getContentLength(downloadUrl);//读取下载文件的字节数
if (contentLength==0){
return TYPE_FAILED;
}else if (contentLength==downloadLength){
return TYPE_SUCCESS;
}
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().addHeader("RANGE","bytes="+downloadLength+"-").url(downloadUrl).build();//head用于告诉服务器我们从那个字节开始下载
Response response=client.newCall(request).execute();
if (response!=null){
is=response.body().byteStream();
savedFile=new RandomAccessFile(file,"rw");
savedFile.seek(downloadLength);//跳过已经下载的字节
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+downloadLength)*100/contentLength);
publishProgress(progress);
}
}
response.body().close();
return TYPE_SUCCESS;
};
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (is!=null){
is.close();
}else if (savedFile!=null){
savedFile.close();
}else if (isCanceled&&file!=null){
file.delete();
}
}catch (Exception e){
e.printStackTrace();
}
}
return TYPE_FAILED;
}
@Override//用于比较下载进度然后使用onProgress来更改下载进度的通知
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.onFiled();
break;
case TYPE_PAUSED:
downloadListener.onPaused();
break;
case TYPE_CANCELED:
downloadListener.inCanceled();
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;
}
}
5)为了保证下载可以一直运行我们需要创建一个服务
package com.example.dowmloadfile.Myservice;
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 com.example.dowmloadfile.MainActivity;
import com.example.dowmloadfile.Myclass.DownLoadTask;
import com.example.dowmloadfile.R;
import com.example.dowmloadfile.imp.DownloadListener;
import java.io.File;
public class DownloadService extends Service {
private DownLoadTask downLoadTask;
private String downloadUrl;
//创建一个DownloadListener并实现其中的方法
private DownloadListener downloadListener=new DownloadListener() {
@Override//以通知的方式显示进度条
public void onProgress(int progress) {
//使用getNotificationManager函数构建一个用于显示下载进度的通知
//使用notify去触发这个通知
getNotificationManager().notify(1,getNotification("Download...",progress));
}
@Override
public void onSuccess() {
downLoadTask=null;
//关闭前台服务通知
stopForeground(true);
getNotificationManager().notify(1,getNotification("download succeed",-1));
Toast.makeText(DownloadService.this,"Download Succeed",Toast.LENGTH_LONG).show();
}
@Override
public void onFiled() {
downLoadTask=null;
//关闭前台服务通知
stopForeground(true);
getNotificationManager().notify(1,getNotification("download filed",-1));
Toast.makeText(DownloadService.this,"Download failed",Toast.LENGTH_LONG).show();
}
@Override
public void onPaused() {
downLoadTask=null;
Toast.makeText(DownloadService.this,"Download Paused",Toast.LENGTH_LONG).show();
}
@Override
public void inCanceled() {
downLoadTask=null;
//关闭前台服务通知
stopForeground(true);
Toast.makeText(DownloadService.this,"Download canceled",Toast.LENGTH_LONG).show();
}
};
private DownloadBinder mBinder=new DownloadBinder();
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
//用于使服务可以和活动通信
public class DownloadBinder extends Binder{
public void startDownload(String url){
if(downLoadTask==null){
downloadUrl=url;
downLoadTask=new DownLoadTask(downloadListener);
//使用execute开启下载
downLoadTask.execute(downloadUrl);
//startForeground使服务成为一个前台服务以创建持续运行的通知
startForeground(1,getNotification("download...",0));
Toast.makeText(DownloadService.this,"Download",Toast.LENGTH_LONG).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_LONG).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();
}
}
6)前台xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" 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 download"/>
<Button
android:id="@+id/pause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="start pause"/>
<Button
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="start cancel"/>
</LinearLayout>
7)MainActivity.java中设置具体逻辑和按钮的触发事件
package com.example.dowmloadfile;
import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
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 com.example.dowmloadfile.Myservice.DownloadService;
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 start=(Button)findViewById(R.id.start);
Button pause=(Button)findViewById(R.id.pause);
Button cancel=(Button)findViewById(R.id.cancel);
start.setOnClickListener(this);
pause.setOnClickListener(this);
cancel.setOnClickListener(this);
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);
}
}
@Override
public void onClick(View view){
if(downloadBinder==null)
{
return;
}
switch (view.getId()){
case R.id.start:
String url="http://icon.nipic.com/BannerPic/20190513/original/20190513111935_1.jpg";
downloadBinder.startDownload(url);
break;
case R.id.pause:
downloadBinder.pauseDownload();
break;
case R.id.cancel:
downloadBinder.cancelDownload();
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
}
8)申请权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />