okhttp实现下载功能
模拟器不能用的话,请用真机测试!!!(
项目太久了就不作回复了,主要是想清理文档了,所以过来备份一下
)
1.导包
implementation 'com.squareup.okhttp3:okhttp:4.0.1'
2.创建Java文件
1.DownloadListener.java
public interface DownloadListener {
void onProgress(int 下载进度);//下载进度
void onSuccess();//下载成功
void onFailed();//下载失败
void onPaused();//下载暂停
void onCanceled();//下载取消
}
2.DownloadService.java
import android.app.Notification;
import android.app.NotificationChannel;
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.Build;
import android.os.Environment;
import android.os.IBinder;
import android.widget.Toast;
import androidx.core.app.NotificationCompat;
import java.io.File;
public class DownloadService extends Service {
//先创建这两个变量
//通知管理器
private NotificationManager notimanger;
private Notification notification;
private DownloadTask downloadTask;
private String downloadurl;
private DownloadListener listener = new DownloadListener() {
@Override
public void onProgress(int 下载进度) {
getNotificationManager().notify(1,getNotification("下载中...",下载进度));
}
@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 onPaused() {
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();
}
};
private DownloadBinder mBuilder =new DownloadBinder();
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBuilder;
}
class DownloadBinder extends Binder {
public void startDownload(String url) {
if (downloadTask == null) {
downloadurl = url;
downloadTask = new DownloadTask(listener);
downloadTask.execute(downloadurl);
startForeground(1, getNotification("下载中...", 0));
Toast.makeText(DownloadService.this, "下载中...", 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, "已取消", Toast.LENGTH_SHORT).show();
}
}
}
}
private Notification getNotification(String title ,int progress) {
//获取系统通知器
notimanger = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//判断低版本系统无法使用
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//创建一个渠道("一个通知"这个随便写)
NotificationChannel noc = new NotificationChannel("notiid", "一个通知", NotificationManager.IMPORTANCE_HIGH);
notimanger.createNotificationChannel(noc);
}
Intent intent = new Intent(this,MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"notiid");//添加渠道
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher));
builder.setSmallIcon(R.drawable.ic_launcher_background);//通知图标,自己准备
builder.setContentIntent(pi);
builder.setContentTitle(title);
if (progress>0){
//当前进度大于0或等于0时显示下载进度
builder.setContentText(progress+"%");
builder.setProgress(100,progress,false);
}
return builder.build();
}
private NotificationManager getNotificationManager() {
return this.notimanger;
}
public DownloadService() {
}
}
3.DownloadTask.java
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 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;
}
@Override
protected Integer doInBackground(String... params) {
InputStream is = null;
RandomAccessFile saveFile = 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 contentLenght= 0;//文件总字节
contentLenght = getContentLenght(downloadurl);
if (contentLenght==0){
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();
saveFile =new RandomAccessFile(file ,"rw");
saveFile.seek(downloadedLength);//跳过已经下载的字节
byte[] b = new byte[1024];
int total = 0;
int len;
while ((len = is.read(b)) != -1){
if (isPaused){
return TYPE_CANCELED;
}else if (isPaused){
return TYPE_PAUSED;
}else {
total +=len;
saveFile.write(b,0,len);
//计算已下载的百分比
int progress = (int) ((total + downloadedLength)*100/contentLenght);
publishProgress(progress);
}
}
response.body().contentLength();
return TYPE_SUCCESS;
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (is!=null){
is.close();
}
if (saveFile!=null){
saveFile.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;
}
super.onProgressUpdate(values);
}
@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;
}
super.onPostExecute(status);
}
public void pauseDownload(){
isPaused = true;
}
public void cancelDownload(){
isCanceled = true;
}
private long getContentLenght(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;
}
}
4.MainActivity.java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.app.Activity;
import android.app.Service;
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;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button 开始,暂停,取消;
private DownloadService.DownloadBinder downloadBinder;
private ServiceConnection serviceConnection =new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
downloadBinder = (DownloadService.DownloadBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
开始 = findViewById(R.id.start);
暂停 = findViewById(R.id.pause);
取消 = findViewById(R.id.cancel);
开始.setOnClickListener(this);
暂停.setOnClickListener(this);
取消.setOnClickListener(this);
Intent intent = new Intent(this,DownloadService.class);
startService(intent);//启动服务
bindService(intent,serviceConnection,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 downloadUI(){
}
@Override
public void onClick(View view) {
if (downloadBinder==null){
return;
}else {
switch (view.getId()){
case R.id.start:
String XZ="http://app.p4p.sogou.com/1/18859786/7918223/e29b11c44d566fc7ead8b809f443eb77/channel_99315971_1122495_e29b11c44d566fc7ead8b809f443eb77.apk?c=0f5d0d470c48f37d15d3fabc1b699e93&sg_vid=Rt0F32_H49t65qPS-gbu5LRO_sXR6CAOo26QmLO66666667rou1R6666666";
downloadBinder.startDownload(XZ);
break;
case R.id.pause:
downloadBinder.pauseDownload();
break;
case R.id.cancel:
downloadBinder.cancelDownload();
break;
default:
break;
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if (grantResults.length>0&& grantResults[0]!= PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"拒绝权限将无法使用程序",Toast.LENGTH_SHORT).show();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
3.创建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"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始下载"
tools:layout_editor_absoluteX="75dp"
tools:layout_editor_absoluteY="60dp"
tools:ignore="MissingConstraints" />
<Button
android:id="@+id/pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停下载"
tools:layout_editor_absoluteX="71dp"
tools:layout_editor_absoluteY="113dp"
tools:ignore="MissingConstraints" />
<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消下载"
tools:layout_editor_absoluteX="75dp"
tools:layout_editor_absoluteY="170dp"
tools:ignore="MissingConstraints" />
</LinearLayout>
4.完成注册表
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mny.myllq">
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
android:usesCleartextTraffic="true"
//这里是安卓10.0必要操作{分区存储},不然无法下载
android:requestLegacyExternalStorage="true">
<meta-data
android:name="com.google.android.actions"
android:resource="@xml/actions" />
//注册服务不用多说了
<service
android:name=".DownloadService"
android:enabled="true"
android:exported="true" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
根据Android 第一行代码(第2版)总结