Home » Android » java – How to prevent UI lag when updating Notification while downloading file?

java – How to prevent UI lag when updating Notification while downloading file?

Posted by: admin June 15, 2020 Leave a comment

Questions:

I am currently using AsyncTask to download a large file in the background within my app, currently the download progress is shown as a ProgressDialog which is updated via onProgressUpdate as below:

protected String doInBackground(String... sUrl) {
        try {
            String destName = sUrl[1];
            file_Delete(destName); // Just to make sure!

            URL url = new URL(sUrl[0]);
            URLConnection connection = url.openConnection();
            connection.connect();
            int fileLength = connection.getContentLength();

            InputStream input = new BufferedInputStream(url.openStream());
            OutputStream output = new FileOutputStream(destName);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;
                publishProgress((int) (total * 100 / fileLength));
                output.write(data, 0, count);
            }

            output.flush();
            output.close();
            input.close();

        } catch (Exception e) {
            Log.e(TAG, NAME + ": Error downloading file! " + e.getMessage());
            return e.getMessage();
        }

        return null;
    }

@Override protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        DownloadImage.mProgressDialog.setProgress(progress[0]);


    }

This works fine, however I now want to use a notification in the notification bar so keep track of the download instead (as the file can be rather large and users would like to keep track from outside the app).

I have tried the below code however the UI starts to lag badly, I can see its due to the publishProgress getting called alot, so how could I go about changing the background code to call publishProgress only every second

@Override protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        DownloadImage.mProgressDialog.setProgress(progress[0]);

        DownloadImage.myNotification = new NotificationCompat.Builder(c)
        .setContentTitle("Downloading SlapOS")
        .setContentText("Download is " + progress[0] + "% done")
        .setTicker("Downloading...")
        .setOngoing(true)
        .setWhen(System.currentTimeMillis())
        .setProgress(100, progress[0], false)
        .setSmallIcon(R.drawable.icon)
        .build();

        DownloadImage.notificationManager.notify(1, DownloadImage.myNotification);

    }
How to&Answers:

so how could I go about changing the background code to call publishProgress only every second

I have done this before for an upload function that showed the % in a Notification, but same exact idea. Have your AsyncTask keep track of what percentDone the download is, and ONLY call publishProgress when percentDone changes. That way, you will only ever call publishProgress when the % downloaded changes, and the Notification therefore needs to update. This should resolve the UI lag.

I was writing this up as my suggested implementation, sounds like the OP already got it working. But maybe this will help someone else in the future:

    byte data[] = new byte[1024];
    long total = 0;
    int count, latestPercentDone;
    int percentDone = -1;
    while ((count = input.read(data)) != -1) {
        total += count;
        latestPercentDone = (int) Math.round(total / fileLength * 100.0);
        if (percentDone != latestPercentDone) {
            percentDone = latestPercentDone;
            publishProgress(percentDone);
        }
        output.write(data, 0, count);
    }

Answer:

I really liked your approach to it! I found that changing the code to the following made my progressbar update correctly. I had some issues while using math.round().

latestPercentDone = (int) ((dataBytesWritten / (float) totalSize) * 100);
    if (percentDone != latestPercentDone) {
    percentDone = latestPercentDone;
    publishProgress(percentDone);
    }