My solution was as follows:
package com.samuelives.videoplayer.downloader;
import android.app.IntentService;
import android.app.NotificationManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.util.Log;
import android.webkit.MimeTypeMap;
import com.samuelives.videoplayer.R;
import com.samuelives.videoplayer.util.StorageHelper;
import com.samuelives.videoplayer.util.Web;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
public class Downloader extends IntentService{
public static final String TARGET_URL = "target_url";
public static final String TARGET_TITLE = "target_title";
private static final int NOTIFICATION_ID = 30101998;
private String title, mURL;
private int downloaded = 0;
public Downloader() {
super("IVP_DOWNLOAD_MANAGER");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
title = intent.getStringExtra(TARGET_TITLE);
mURL = intent.getStringExtra(TARGET_URL);
try {
URL url = new URL(mURL);
download(url);
}catch (MalformedURLException e){
Log.e("Downloader", "Falha ao criar a URL: " + e.getMessage());
}
}
private void download(final URL url){
new Thread(new Runnable() {
HttpURLConnection conn;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
@Override
public void run() {
try{
conn = (HttpURLConnection)url.openConnection();
conn.setRequestProperty("User-Agent", Web.getUserAgent(Downloader.this));
FileOutputStream fos;
File dFile = new File(Uri.parse(getDestPath()).getPath());
if(!dFile.exists()){
fos = new FileOutputStream(dFile);
}else{
conn.setRequestProperty("Range", "bytes=" + dFile.length() + "-");
downloaded = (int)dFile.length();
fos = new FileOutputStream(dFile, true);
}
conn.connect();
if(processResponse(conn.getResponseCode(), conn.getResponseMessage())) {
int totalSize = conn.getContentLength();
NotificationCompat.Builder notification = new NotificationCompat.Builder(Downloader.this, "IVP_NOTIFICATION_CHANEL")
.setSmallIcon(R.drawable.ic_download)
.setContentTitle(getResources().getString(R.string.dm_downloading_msg))
.setContentText(title)
.setProgress(totalSize, 0, false)
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setOnlyAlertOnce(true);
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notification.build());
bis = new BufferedInputStream(conn.getInputStream());
bos = new BufferedOutputStream(fos, 1024);
byte[] data = new byte[1024];
int pos = 0;
synchronized(this){
while ((pos = bis.read(data, 0, 1024)) != -1) {
downloaded += pos;
bos.write(data, 0, pos);
Thread.sleep(1000);
Log.d("Downloader", "Baixados: " + 100 * downloaded / totalSize + "% .");
notification.setProgress(totalSize, downloaded, false);
notificationManager.notify(NOTIFICATION_ID, notification.build());
}
}
notification.setProgress(0, 0, false);
notificationManager.notify(NOTIFICATION_ID, notification.build());
}
}catch (IOException | InterruptedException e){
Log.e("Downloader", "Falha ao baixar o arquivo: " + e.getMessage());
}finally {
if(conn != null)
conn.disconnect();
try{
if(bis != null)
bis.close();
if(bos != null){
bos.flush();
bos.close();
}
}catch (IOException e){
Log.e("Downloader", "Falha ao encerrar os buffers: " + e.getMessage());
}
}
}
}).start();
}
private String getDestPath(){
String destPath = null;
if(StorageHelper.haveSdCard(this)){
File storageDir = StorageHelper.getStorage(this);
if(!storageDir.exists()){
storageDir.mkdirs();
}
Log.i("Downloader", "Download path: " + storageDir.getAbsolutePath());
destPath = new File(storageDir.getPath(), title + "." + MimeTypeMap.getFileExtensionFromUrl(mURL)).getAbsolutePath();
Log.i("Downloader", "Dest file: " + destPath);
}else{
destPath = new File(StorageHelper.getInternalStorage(this), title + "." +MimeTypeMap.getFileExtensionFromUrl(mURL)).getAbsolutePath();
Log.i("Downloader", "Dest file: " + destPath);
}
return destPath;
}
private boolean processResponse(int code, String message){
boolean ok = true;
switch(code){
case 405:
Log.e("Downloader", "Response code: " + code + " "+ message);
ok = false;
break;
default:
Log.d("Downloader", "Response code: " + code + " " + message);
break;
}
return ok;
}
}
As I read in the notification documentation, updating the notification very frequently can lead to system crashes, so I added short breaks and the problem was resolved.