Search code examples
javaandroidmultithreadingandroid-download-managerandroid-toast

Why is the Toast not hidden after the time period ended?


I have created a small app that downloads a file using the download manager.
All ok so far.
I thought to add a small Toast and show the user the current status of the download.
So I did something like the following:

Thread t = new Thread(new Runnable() {
    @Override
    public void run() {
         int status = -1;
         while ( (status = checkDownloadStatus()) != -1 && status != DownloadManager.STATUS_FAILED && status != DownloadManager.STATUS_SUCCESSFUL) {
                    try {
                        Log.d("MyApp", "Sleeping for 500 while polling for status [ " + status + " ]");
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.e("MyApp", e.getLocalizedMessage());
                    }
                }
                Log.d("MyApp", "Stop sleeping!");
            }
 });
 t.start();

Inside the checkDownloadStatus I show a Toast to the user about the status of the download: e.g. STARTED/PENDING/FINISHED

I see that the download is in progress and I see the Toast during the download and in the logs I see:

Sleeping for 500 while polling for status [ 2 ]  
Sleeping for 500 while polling for status [ 2 ]  
Sleeping for 500 while polling for status [ 2 ]  
Sleeping for 500 while polling for status [ 2 ]  
…..

Then when the download is complete I see in the log:

Stop sleeping!

But the Toast with the last msg is still displayed.

What am I doing wrong? Is there a better way to achieve what I need

UPDATE:

private int checkDownloadStatus() {

        final Cursor c= dm.query(new DownloadManager.Query().setFilterById(downloadId));
        if (c == null) {
            showUserStatus(getActivity().getString(R.string.download_not_found), Toast.LENGTH_LONG);
        }
        else {
            c.moveToFirst();
            final int status = showStatusMessage(c);
            c.close();
            return status;
        }
        return -1;
    }


private int showStatusMessage(Cursor c) {
        String msg="???";
        int downloadStatus = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
        switch (downloadStatus) {
            case DownloadManager.STATUS_FAILED:
                msg= getActivity().getString(R.string.download_failed);
                break;

            case DownloadManager.STATUS_PAUSED:
                msg= getActivity().getString(R.string.download_paused);
                break;

            case DownloadManager.STATUS_PENDING:
                msg= getActivity().getString(R.string.download_pending);
                break;

            case DownloadManager.STATUS_RUNNING:
                msg= getActivity().getString(R.string.download_in_progress);
                break;

            case DownloadManager.STATUS_SUCCESSFUL:
                msg= getActivity().getString(R.string.download_complete);
                break;

            default:
                msg= getActivity().getString(R.string.download_is_nowhere_in_sight);
                break;
        }
        showUserStatus(msg, Toast.LENGTH_LONG);
        return downloadStatus;
    }


private void showUserStatus(final String msg, final int length) {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getActivity(), msg, length).show();
            }
        });
    }

Solution

  • Toast are queued. If you call showText with the same text n times, you will see a toast with the same text for n * length time. Keep a reference to the current Toast and call Toast.cancel() before showing the next one.

    E.g.

    Toast mToast; 
    
    private void showUserStatus(final String msg, final int length) {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (mToast != null) {
                        mToast.cancel();
                    }
                    mToast = Toast.makeText(getActivity(), msg, length);
                    mToast.show();
                }
            });
        }