servicebesttest

学习目的:1.完整版下载示例 (@verride表示重写方法 无则是新建方法)

添加依赖

1
compile 'com.squareup.okhttp3:okhttp:3.4.1'

定义一个回调接口(对下载过程中的各种状态进行监听和回调)
DownloadListenter

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface DownloadListener {

void onProgress(int progress);

void onSuccess();

void onFailed();

void onPaused();

void onCanceled();

}

AsynsTask实现下载功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//三个参数 传入数据 进度显示数据单位 反馈执行结果数据类型
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;
}
//下载逻辑
@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("/"));
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;
}
//界面显示当前下载进度
@Override
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
if (progress > lastProgress) {
listener.onProgress(progress);
lastProgress = progress;
}
}
//通知最终下载结果
@Override
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();
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;
}

创建下载服务DownloadService(重写5个方法) DownloadBinder内部类(重写3个方法)两个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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;
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();

@Override
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) {
// 当progress大于或等于0时才需显示下载进度
builder.setContentText(progress + "%");
builder.setProgress(100, progress, false);
}
return builder.build();
}

}

MainActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private DownloadService.DownloadBinder downloadBinder;

private ServiceConnection connection = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName name) {
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (DownloadService.DownloadBinder) service;
}

};

@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(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 v) {
if (downloadBinder == null) {
return;
}
switch (v.getId()) {
case R.id.start_download:
String url = "https://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, 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:
}
}

@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}

}

权限声明


<service
    android:name=".DownloadService"
    android:enabled="true"
    android:exported="true" />