Android- download file + status bar notification slowing down phone

14,272

Solution 1

I saw similar results, you need to not push the update the notification so often, i changed mine to update only update a few times a second. (e.g. in onProgressUpdate keep track of the last time you called notify, and only call notify if you're past 100ms of the previous call, or if you're at the max value.

Solution 2

I had similar issue once, I solved it using CountDownTimer.

Similar to how @superfell suggested, you can call progress update of AsyncTask regularly while downloading file. And call the Notification Manager only at specific interval.

After calling start() of CountDownTimer, it will call onTick() function after every fixed interval of time, and will call onFinish() either when timer is timed out or when called explicitly. cancel() function will only cancel the timer and will not call onFinish() method.

class DownloadMaterial extends AsyncTask<String, String, String> {

    CountDownTimer cdt;
    int id = i;
    NotificationManager mNotifyManager;
    NotificationCompat.Builder mBuilder;

    @Override
    protected void onPreExecute() {
        /**
         * Create custom Count Down Timer
         */
        cdt = new CountDownTimer(100 * 60 * 1000, 500) {
            public void onTick(long millisUntilFinished) {
                mNotifyManager.notify(id, mBuilder.build());
            }

            public void onFinish() {
                mNotifyManager.notify(id, mBuilder.build());
            }
        };
    }

    @Override
    protected String doInBackground(String... strings) {
        /**
         * Start timer to update Notification
         * Set Progress to 20 after connection
         * Build Notification
         * Increment Progress
         * Download and Save file
         */
        try {
            mNotifyManager =
                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            mBuilder = new NotificationCompat.Builder(context);
            mBuilder.setContentTitle("Downloading File")
                    .setContentText(file_name)
                    .setProgress(0, 100, false)
                    .setOngoing(true)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setPriority(Notification.PRIORITY_LOW);

            // Initialize Objects here
            publishProgress("5");
            mNotifyManager.notify(id, mBuilder.build());
            cdt.start();

            // Create connection here
            publishProgress("20");

            // Download file here
            while ((count = input.read(data)) != -1) {
                total += count;
                publishProgress("" + (int) (20 + (total * 80 / fileLength)));
                output.write(data, 0, count);
            }
        } catch (Exception e) {
            return "Failed";
        }
        return "Success";
    }

    @Override
    protected void onProgressUpdate(String... values) {
        /**
         * Update Download Progress
         */
        mBuilder.setContentInfo(values[0] + "%")
                .setProgress(100, Integer.parseInt(values[0]), false);
    }

    @Override
    protected void onPostExecute(String s) {

        String title;
        if (s.equals("Success")) {
            title = "Downloaded";
        } else {
            title = "Error Occurred";
        }
        mBuilder.setContentTitle(title)
                .setContentInfo("")
                .setOngoing(false)
                .setProgress(0, 0, false);
        cdt.onFinish();
        cdt.cancel();
    }
}

It is a good practice to call onFinish() first and then call cancel().

Solution 3

I too experienced this problem. I was updating the progress bar WAY too often (even when the progress didn't change), here's how I fixed that:

        // While loop from generic download method.
        int previousProgress = 0;
        while ((count = inputStream.read(buff)) != -1) {
            outputStream.write(buff, 0, count);
            totalBytesDownloaded += count;
            int prog = (int) (totalBytesDownloaded * 100 / contentLength);
            if (prog > previousProgress) {
                // Only post progress event if we've made progress.
                previousProgress = prog;
                myPostProgressMethod(prog);

            }
        }

Now the app runs great and the user still receives a progress notification.

Share:
14,272
Splitusa
Author by

Splitusa

Updated on June 04, 2022

Comments

  • Splitusa
    Splitusa almost 2 years

    I currently have an asynctask which downloads a mp3 from a server. When the user starts to download it, a status bar notification is created. This displays the progress of the download in real time. My only concern is that the phone slows down almost too much. Is there any way to delay the progress displayed or a way to make my code faster? Thanks.

    Code below:

    public class DownloadFile extends AsyncTask<String, String, String> {
        CharSequence contentText;
        Context context;
        CharSequence contentTitle;
        PendingIntent contentIntent;
        int HELLO_ID = 1;
        long time;
        int icon;
        CharSequence tickerText;
        File file;
    
        public void downloadNotification() {
            String ns = Context.NOTIFICATION_SERVICE;
            notificationManager = (NotificationManager) getSystemService(ns);
    
            icon = R.drawable.sdricontest;
            //the text that appears first on the status bar
            tickerText = "Downloading...";
            time = System.currentTimeMillis();
    
            notification = new Notification(icon, tickerText, time);
    
            context = getApplicationContext();
            //the bold font
            contentTitle = "Your download is in progress";
            //the text that needs to change
            contentText = "0% complete";
            Intent notificationIntent = new Intent(Intent.ACTION_VIEW);
            notificationIntent.setType("audio/*");
            contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
    
            notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
            notificationManager.notify(HELLO_ID, notification);
        }
    
        @Override
        protected void onPreExecute() {
            //execute the status bar notification
            downloadNotification();
            super.onPreExecute();
        }
    
        @Override
        protected String doInBackground(String... url) {
            int count;
            try {
                URL url2 = new URL(sdrUrl);
                HttpURLConnection connection = (HttpURLConnection) url2.openConnection();
                connection.setRequestMethod("GET");
                connection.setDoOutput(true);
                connection.connect();
    
                int lengthOfFile = connection.getContentLength();
    
                //make the stop drop rave folder
                File sdrFolder = new File(Environment.getExternalStorageDirectory() + "/StopDropRave");
                boolean success = false;
    
                if (!sdrFolder.exists()) {
                    success = sdrFolder.mkdir();
                }
                if (!success) {
                    String PATH = Environment.getExternalStorageDirectory()
                            + "/StopDropRave/";
                    file = new File(PATH);
                    file.mkdirs();
                } else {
                    String PATH = Environment.getExternalStorageDirectory()
                            + "/StopDropRave/";
                    file = new File(PATH);
                    file.mkdirs();
                }
    
                String[] path = url2.getPath().split("/");
                String mp3 = path[path.length - 1];
                String mp31 = mp3.replace("%20", " ");
                String sdrMp3 = mp31.replace("%28", "(");
                String sdrMp31 = sdrMp3.replace("%29", ")");
                String sdrMp32 = sdrMp31.replace("%27", "'");
    
                File outputFile = new File(file, sdrMp32);
                FileOutputStream fos = new FileOutputStream(outputFile);
    
                InputStream input = connection.getInputStream();
    
                byte[] data = new byte[1024];
                long total = 0;
                while ((count = input.read(data)) != -1) {
                    total += count;
                    publishProgress("" + (int) (total * 100 / lengthOfFile));
                    fos.write(data, 0, count);
                }
                fos.close();
                input.close();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        public void onProgressUpdate(String... progress) {
            contentText = Integer.parseInt(progress[0]) + "% complete";
            notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
            notificationManager.notify(HELLO_ID, notification);
            super.onProgressUpdate(progress);
        }
    }
    
  • dmon
    dmon almost 13 years
    Yep, you're publishing too many notifications. Try updating only after the percentage has actually changed at least 1%.
  • Splitusa
    Splitusa almost 13 years
    Sounds good. Would you happen to have some sample code or just an idea of how I can implement it?
  • Splitusa
    Splitusa almost 13 years
    @dmon - how could i track this?
  • dmon
    dmon almost 13 years
    Well, just add an int variable and before publishProgress, e.g. if ((int) (total * 100 / lengthOfFile) > previousProgress) { previousProgress = (int) (total * 100 / lengthOfFile); publishProgress(...); }
  • Splitusa
    Splitusa almost 13 years
    so I added this in my while loop: int prevprogress = (int) (total * 100 / lengthOfFile); if ((int) (total * 100 / lengthOfFile) > prevprogress) { prevprogress = (int) (total * 100 / lengthOfFile); publishProgress(""+(int) (total * 100 / lengthOfFile)); fos.write(data, 0, count); Its still running pretty slow. did i do it correctly???
  • Moss
    Moss about 12 years
    Instead of using the percentage I would use both the percentage itself and a time value. If you are only handling the percentage when downloading small files you will push again too many notification updates. So the use of both contidions would be the best way to go.
  • Martin Pfeffer
    Martin Pfeffer almost 8 years
    thanks, but the small icon is missing... so you may want to add e.g. ".setSmallIcon(R.mipmap.ic_launcher)"
  • Lalit Umbarkar
    Lalit Umbarkar almost 8 years
    @MartinPfeffer Thanks. Edited accordingly.
  • Vahid Amiri
    Vahid Amiri almost 7 years
    Still, this is not enough if the download servers are too fast.
  • Sakiboy
    Sakiboy almost 7 years
    @VSG24, huh? How about updating the UI/progress-notification even less then? It's not the "too fast" servers fault, it's probably your code, to be honest.