Search code examples
androidandroid-asynctaskbusy-waiting

Waiting Dialog doesn't works correctly and the app freezes until the task end


I have a class that sends various mail with attachments.

Because the method sendEmail(addresses); requires time to upload the attachments and send the emails, I have created an AsyncTask to show a waiting dialog,

however, unfortunately, during the sending the app freezes until it has terminated the sending without showing anything (or sometimes shows a frozen waiting windows for a little instant before the end of procedure)

The related parts of code in my class are the follows

public class MyClass extends Activity {
    ...

    private ProgressDialog waitingDialog;

    ....

    OnClickListener mInvia = new OnClickListener() {
        public void onClick(View v) {
                new MyAsyncTaskClass().execute(new String[] {});
        }
    };

    public void prepareSending() {
        String x = "";
        for (String s : selectedMails) {
            x += (s + ";");
        }
        String[] addresses = x.split(";");
        sendEmail(addresses);
    }

    private void openFile() {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.setType("file/*");
        startActivityForResult(i, FILE_REQ_CODE);
    }

    protected void onActivityResult(int requestCode, int resultCode,
            Intent intentData) {

        Uri tmp = intentData.getData();
        filePath=getRealPath(tmp);
        super.onActivityResult(requestCode, resultCode, intentData);

    }


    public void sendEmail(String[] addresses) {

        Mail m = new Mail("sendermail@sample.com",
                "senderpassword");

        name = editor1.getText().toString();
        subject = editor2.getText().toString();
        text = editor3.getText().toString();
        emailReply = editor4.getText().toString();

        m.setTo(addresses);
        m.setFrom(emailReply);
        m.setSubject(subject);
        m.setBody(text + "\n\n\n Sent by" + name);
        try {
            m.send();
        } catch (Exception e) {
            Log.e("MyClass", "Cannot send email", e);
        }

        try {
            m.addAttachment(filePath);

            if (m.send()) {
                Alerts.Ok(MyClass.this);
                nSuccess++;
            } else {
                Alerts.ErrorSending(MyClass.this);
            }
        } catch (Exception e) {
            Alerts.ErrorAttachment(MyClass.this);
        }

    }

    //inner class that should show a waiting windows
    private class MyAsyncTaskClass extends AsyncTask<String, Void, Void> {

        @Override
        protected void onPreExecute() {
            waitingDialog = new ProgressDialog(MyClass.this);
            waitingDialog.setMessage("Loading ....");
            waitingDialog.setIndeterminate(true);
            waitingDialog.setCancelable(true);
            waitingDialog.show();
        }

        @Override
        protected Void doInBackground(final String... strings) {
            try {
                runOnUiThread(new Runnable() {
                    public void run() {
                        prepareSending();
                    }

                });
            } catch (Exception e) {

            }
            return null;
        }

        @Override
        protected void onPostExecute(Void params) {
            waitingDialog.dismiss();
        }
    }

    //end innerclass
    // start context menu code
    ......

}

Solution

  • Problem

    I'd wager it's because you're running everything on the UI thread:

        @Override
        protected Void doInBackground(final String... strings) {
            try {
                runOnUiThread(new Runnable() {
                    public void run() {
                        prepareSending();
                    }
    
                });
            } catch (Exception e) {
    
            }
            return null;
        }
    

    Do this instead!

    Run all your doInBackground code based on non-UI-reliant things.

        @Override
        protected Void doInBackground(final String... strings) {
            prepareSending();
            return null;
        }
    

    Accessing the UI

    If you need to access data from the UI, or anything else on the UI thread, do that first.

        protected void onPreExecute() {
            // Find all your "editor" fields here, and save them to member variables within the AsyncTask.
            // ...
        }
    

    Then send those to your method

    In prepareSending and sendEmail accept that data as parameters:

    public void prepareSending(String name, String subject, String text, String emailReply) {
        // ...
        sendEmail(addresses, name, subject, text, emailReply);
    }
    public void sendEmail(String[] addresses, String name, String subject, String text, String emailReply) {
        // ...
    }
    

    And lastly, you need to send those from doInBackground:

        @Override
        protected Void doInBackground(final String... strings) {
            prepareSending(mName, mSubject, mText, mEmailReply); // The local fields you saved earlier
            return null;
        }