Android - Notification bar hangs while updating progress

Asked

Viewed 48 times

0

I have an application that uses a custom download manager, I’m trying to show a progress bar in a notification, but every time you enter the while loop I can’t scroll down the notification bar and the device starts crashing:

private void downloadWithHTTPS(@NonNull URL url){

    HttpsURLConnection conn = null;

    try{

        int downloaded = 0;

        File dFile = new File(Uri.parse(getDestPath()).getPath());

        conn = (HttpsURLConnection)url.openConnection();

        if(conn == null)
            return;

        conn.setRequestProperty("User-Agent", userAgent);

        FileOutputStream fos;

        if(dFile.exists()){
            conn.setRequestProperty("Range", "bytes=" + dFile.length() + "-");
            downloaded = (int)dFile.length();
            fos = new FileOutputStream(dFile, true);
        }else{
            fos = new FileOutputStream(dFile);
        }

        conn.connect();

        processResponse(conn.getResponseCode(), conn.getResponseMessage());

        BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);

        Log.i("Downloader", "Total file length: " + conn.getContentLength());

        byte[] data = new byte[1024];
        int pos = 0;

        while((pos = bis.read(data, 0, 1024)) >= 0){

            downloaded += pos;

            bos.write(data, 0, pos);
            mNotification.setContentText("Baixando " + downloaded / 100 + "%");
            mNotification.setProgress(downloaded, pos, false);
            mNotManager.notify(NOTIFICATIONS_ID, mNotification.build());
        }

        bos.flush();
        bos.close();
        bis.close();


        mNotification.setContentText("Baixado");
        mNotification.setProgress(0, 0, false);
        mNotManager.notify(NOTIFICATIONS_ID, mNotification.build());

    }catch (IOException e){
        Log.e("Downloader", "Could not download file: " + e.getMessage());
    }finally {
        if(conn != null)
            conn.disconnect();
    }

}
  • 1

    Tried to create a thread or doInBackground? See: https://developer.android.com/reference/android/os/AsyncTask

  • I used a thread and Sleep for 5000 milliseconds, but an error indicates that Inputstream was closed

  • But there is already "another" error, no detailed log gets a little complicated

  • When reading the Notifications documentation I found the cause of my error, https://developer.android.com/training/notify-user/build-notification, by updating the notifications very often the system may crash, a solution would actually be the thread but create a gap for the while loop

1 answer

0

My solution was this::

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 read in the notification documentation, updating the notification very often can lead to system crashes, so I added small ranges and the problem was solved.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.