
ServiceBestActivity.java
package cn.edu.zufe.app002;
import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import cn.edu.zufe.app002.service.DownloadService;
public class ServiceBestActivity extends AppCompatActivity implements View.OnClickListener{
private Button btnStart;
private Button btnPause;
private Button btnCancle;
private DownloadService.DownloadBinder downloadBinder;
private ServiceConnection connection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service_best);
btnStart = (Button) findViewById(R.id.btn_start);
btnPause = (Button) findViewById(R.id.btn_pause);
btnCancle = (Button) findViewById(R.id.btn_cancle);
connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (DownloadService.DownloadBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
btnStart.setOnClickListener(this);
btnPause.setOnClickListener(this);
btnCancle.setOnClickListener(this);
Intent intent = new Intent(this, DownloadService.class);
bindService(intent, connection, BIND_AUTO_CREATE);
if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(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.btn_start:
String url = "http://jackie.vaiwan.com/cn.edu.zufe.app002/Java1.pdf";
downloadBinder.startDownload(url);
break;
case R.id.btn_pause:
downloadBinder.pauseDownload();
break;
case R.id.btn_cancle:
downloadBinder.cancleDownload();
break;
default:
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if(grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "拒绝权限无法使用程序", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
break;
}
}
}
activity_service_best.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ServiceBestActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_start"
android:text="开始" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_pause"
android:text="暂停" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_cancle"
android:text="取消" />
</LinearLayout>
DownloadTask.java
package cn.edu.zufe.app002.bean;
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 cn.edu.zufe.app002.interfaci.DownloadListener;
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_FAIL = 1;
public static final int TYPE_CANCLE = 2;
public static final int TYPE_PAUSE = 3;
private DownloadListener listener;
private boolean isCancled = 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 downloadLength = 0;
String downloadUrl = strings[0];
String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
if(file.exists()) downloadLength = file.length();
long contentLength = getContentLength(downloadUrl);
if(contentLength == 0) return TYPE_FAIL;
else if(contentLength == downloadLength) return TYPE_SUCCESS;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.addHeader("RANGE", "bytes=" + downloadLength + "-")
.url(downloadUrl)
.build();
Response response = client.newCall(request).execute();
if(response != null) {
is = response.body().byteStream();
savedFile = new RandomAccessFile(file, "rw");
savedFile.seek(downloadLength);
byte[] buf = new byte[1024];
int len;
int total = 0;
while ((len = is.read(buf)) != -1) {
if(isPaused) return TYPE_PAUSE;
else if(isCancled) return TYPE_CANCLE;
savedFile.write(buf, 0, len);
total += 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();
if(savedFile != null) savedFile.close();
if(isCancled && file != null) file.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
return TYPE_FAIL;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int progress = values[0];
if(progress > lastProgress) {
lastProgress = progress;
listener.onProgress(progress);
}
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
switch (integer) {
case TYPE_SUCCESS:
listener.onSuccess();
break;
case TYPE_FAIL:
listener.onFail();
break;
case TYPE_PAUSE:
listener.onPause();
break;
case TYPE_CANCLE:
listener.onCancle();
break;
default:
break;
}
}
public void pauseDownload() {
isPaused = true;
}
public void cancleDownload() {
isCancled = 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()) {
return response.body().contentLength();
}
return 0;
}
}
DownloadListener.java
package cn.edu.zufe.app002.interfaci;
public interface DownloadListener {
public void onProgress(int progress);
public void onSuccess();
public void onPause();
public void onFail();
public void onCancle();
}
DownloadService.java
package cn.edu.zufe.app002.service;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import java.io.File;
import cn.edu.zufe.app002.R;
import cn.edu.zufe.app002.bean.DownloadTask;
import cn.edu.zufe.app002.interfaci.DownloadListener;
public class DownloadService extends Service {
private String downloadUrl;
private DownloadTask downloadTask;
private DownloadListener listener;
private NotificationManager manager;
private NotificationChannel channel;
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onCreate() {
super.onCreate();
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
channel = new NotificationChannel("channel1", "channel1", NotificationManager.IMPORTANCE_LOW);
channel.setSound(null, null);
manager.createNotificationChannel(channel);
listener = new DownloadListener() {
@Override
public void onProgress(int progress) {
manager.notify(1, getNotification("Downloading...", progress));
}
@Override
public void onSuccess() {
downloadTask = null;
stopForeground(true);
Toast.makeText(DownloadService.this, "Download successed", Toast.LENGTH_SHORT).show();
}
@Override
public void onPause() {
downloadTask = null;
Toast.makeText(DownloadService.this, "Download paused", Toast.LENGTH_SHORT).show();
}
@Override
public void onFail() {
downloadTask = null;
stopForeground(true);
Toast.makeText(DownloadService.this, "Download Failed", Toast.LENGTH_SHORT).show();
}
@Override
public void onCancle() {
downloadTask = null;
stopForeground(true);
Toast.makeText(DownloadService.this, "Download Cancled", Toast.LENGTH_SHORT).show();
}
};
}
private Notification getNotification(String title, int progress) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "default");
builder.setChannelId("channel1");
builder.setContentTitle(title);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.happy));
if(progress > 0) {
builder.setOnlyAlertOnce(true);
builder.setContentText(progress + "%");
builder.setProgress(100, progress, false);
}
return builder.build();
}
public DownloadService() {
}
private DownloadBinder mBinder = new DownloadBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class DownloadBinder extends Binder {
public void startDownload(String url) {
if(downloadTask == null) {
downloadTask = new DownloadTask(listener);
downloadUrl = url;
downloadTask.execute(url);
startForeground(1, getNotification("Downloading...", 0));
Toast.makeText(DownloadService.this, "Downloading...", Toast.LENGTH_SHORT).show();
}
}
public void pauseDownload() {
if(downloadTask != null) downloadTask.pauseDownload();
}
public void cancleDownload() {
if(downloadTask != null) downloadTask.cancleDownload();
else {
if(downloadUrl != null) {
String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
if(file.exists()) file.delete();
stopForeground(true);
manager.cancel(1);
Toast.makeText(DownloadService.this, "Download Cancled", Toast.LENGTH_SHORT).show();
}
}
}
}
}