La finestra di dialogo in attesa non funziona correttamente e l'app si blocca fino alla fine dell'attività
-
13-12-2019 - |
Domanda
Ho una classe che invia varie mail con allegati.
Poiché il metodo sendEmail(addresses);
richiede il tempo di caricare gli allegati e inviare le e-mail, ho creato un asynctask per mostrare una finestra di dialogo d'attesa,
Tuttavia, sfortunatamente, durante l'invio dell'app si blocca fino a quando non ha terminato l'invio senza mostrare nulla (o talvolta mostra un avviso congelato per un piccolo istante prima della fine della procedura)
Le parti correlate del codice nella mia classe sono i seguenti
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
......
}
. Soluzione
Problema
Wager è perché stai correndo tutto sul filo Ui:
@Override
protected Void doInBackground(final String... strings) {
try {
runOnUiThread(new Runnable() {
public void run() {
prepareSending();
}
});
} catch (Exception e) {
}
return null;
}
.
fai questo invece!
Esegui tutto il tuo codice doInBackground
basato su cose non-interfacciate.
@Override
protected Void doInBackground(final String... strings) {
prepareSending();
return null;
}
.
Accesso all'UI
Se è necessario accedere ai dati dall'interfaccia utente, o per qualsiasi altra cosa sulla filettatura dell'interfaccia utente, fai questo prima .
protected void onPreExecute() {
// Find all your "editor" fields here, and save them to member variables within the AsyncTask.
// ...
}
.
quindi invia quelli al tuo metodo
in prepareSending
e sendEmail
accettano i dati come parametri:
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) {
// ...
}
.
E infine, è necessario inviare quelli da doInBackground
:
@Override
protected Void doInBackground(final String... strings) {
prepareSending(mName, mSubject, mText, mEmailReply); // The local fields you saved earlier
return null;
}
. Altri suggerimenti
Questo non è il modo consigliato di fare:
@Override
protected Void doInBackground(final String... strings) {
try {
runOnUiThread(new Runnable() {
public void run() {
prepareSending();
}
});
} catch (Exception e) {
}
return null;
}
.
Dovresti usare PublishProgress () per poter eseguire cose sul thread dell'interfaccia utente mentre la tua lavorazione sta succedendo.
Detto questo, non si sta gestendo i casi in cui l'attività può essere distrutta.Ciò potrebbe portare a perdite di memoria e a più asynctasks in esecuzione sullo sfondo.
prova ad arrivare a qualcosa del genere:
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;
}
.
La tua attività è rispostiva per salvare l'attività come stato di non-istanza, chiusura e ricreare la finestra di dialogo quando appropriato, ...
Infine, passa tutte le informazioni necessarie per inviare la posta al costruttore del tuo compito (contenuto, soggetto, ...).Tutti gli accessi interfacciari verranno eseguiti sulla filettatura dell'interfaccia utente quando si crea l'attività (non in downbackground come fai a riguardo).
I problemi bugie qui:
try {
runOnUiThread(new Runnable() {
public void run() {
prepareSending();
}
});
} catch (Exception e) {
}
.
1) preparazione ();Il metodo è chiamato sul filo UI.Segnala per capire come usare asynctask In Android
2) Sembra anche che tu abbia l'abitudine di catturare eccezioni generiche e anche non gestirle.Fare riferimento a Guideline di stile .Ti aiuterà molto.
Buona fortuna;)
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) {
}
}
.