Reputation: 12385
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("[email protected]",
"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
......
}
Upvotes: 0
Views: 199
Reputation: 399
private class MyAsyncTaskClass extends AsyncTask<String, Integer, Integer> {
ProgressDialog waitingDialog;
@Override
protected void onPreExecute() {
waitingDialog = new ProgressDialog(MyClass.this);
waitingDialog.setMessage("Loading ....");
waitingDialog.setIndeterminate(true);
waitingDialog.setCancelable(true);
}
@Override
protected Integer doInBackground(final String... strings) {
setProgress(-1);
// long process start
prepareSending();
// long process end
setProgress(-2);
return 0;
}
@Override
protected void onProgressUpdate(Integer... values) {
if (values[0] == -1) {
waitingDialog.show();
} else if (values[2] == -2) {
waitingDialog.dismiss();
}
}
@Override
protected Integer onPostExecute(Integer params) {
}
}
Upvotes: 0
Reputation: 2581
Problems lies here:
try {
runOnUiThread(new Runnable() {
public void run() {
prepareSending();
}
});
} catch (Exception e) {
}
1) prepareSending(); method is called on the UI thread. Refer this to understand how to use AsyncTask in Android
2) Also it seems like you have habit of catching generic exceptions and also not handling them. Refer Code Style Guidelines. It will help you a lot.
Good Luck ;)
Upvotes: 0
Reputation: 28541
This is not the recommended way of doing:
@Override
protected Void doInBackground(final String... strings) {
try {
runOnUiThread(new Runnable() {
public void run() {
prepareSending();
}
});
} catch (Exception e) {
}
return null;
}
You should use publishProgress() in order to run stuff on the UI thread as your processing is going on.
That said, you are also not managing the cases where the activity can be destroyed. This could lead to memory leaks and multiple AsyncTasks running in the background.
Try to get to something like:
public static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
MyAsyncTask(MyActivity a) {
activity = new WeakReference<MyActivity>(a);
}
@Override
protected void onPreExecute() {
if (activity.get()!=null) activity.get().showDialog();
}
@Override
protected Void doInBackground(Void... params) {
// Upload data from here
}
@Override
protected void onPostExecute(Void params) {
if (activity.get()!=null) activity.get().dismissDialog();
}
private WeakReference<MyActivity> activity;
}
Your activity is respondible for saving the task as a non-instance state, closing and recreating the dialog when appropriate, ...
Finally, pass all the information needed to send the mail to your task constructor (content, subject, ...). All the UI accesses will then be done on the UI thread when you create the task (not in doInBackground as you do curently).
Upvotes: 0
Reputation: 67512
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;
}
Run all your doInBackground
code based on non-UI-reliant things.
@Override
protected Void doInBackground(final String... strings) {
prepareSending();
return null;
}
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.
// ...
}
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;
}
Upvotes: 2