Sì, il concetto di callback esiste anche in Java. In Java si definisce un callback come questo:
public interface TaskListener {
public void onFinished(String result);
}
Uno sarebbe spesso nido questo tipo di definizioni ascoltatore all'interno del AsyncTask
in questo modo:
public class ExampleTask extends AsyncTask<Void, Void, String> {
public interface TaskListener {
public void onFinished(String result);
}
...
}
E una completa implementazione della richiamata nella AsyncTask
guarderebbe in questo modo:
public class ExampleTask extends AsyncTask<Void, Void, String> {
public interface TaskListener {
public void onFinished(String result);
}
// This is the reference to the associated listener
private final TaskListener taskListener;
public ExampleTask(TaskListener listener) {
// The listener reference is passed in through the constructor
this.taskListener = listener;
}
@Override
protected String doInBackground(Void... params) {
return doSomething();
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// In onPostExecute we check if the listener is valid
if(this.taskListener != null) {
// And if it is we call the callback function on it.
this.taskListener.onFinished(result);
}
}
}
onPostExecute()
è chiamato non appena l'attività in background termina. È possibile utilizzare l'intera cosa come questa:
ExampleTask task = new ExampleTask(new ExampleTask.TaskListener() {
@Override
public void onFinished(String result) {
// Do Something after the task has finished
}
});
task.execute();
Oppure si può definire la TaskListener
completamente a parte in questo modo:
ExampleTask.TaskListener listener = new ExampleTask.TaskListener() {
@Override
public void onFinished(String result) {
// Do Something after the task has finished
}
};
ExampleTask task = new ExampleTask(listener);
task.execute();
Oppure si può creare una sottoclasse TaskListener
in questo modo:
public class ExampleTaskListener implements TaskListener {
@Override
public void onFinished(String result) {
}
}
E quindi utilizzarlo in questo modo:
ExampleTask task = new ExampleTask(new ExampleTaskListener());
task.execute();
È possibile naturalmente solo l'override del metodo del AsyncTask
onPostExecute()
, ma questo non è raccomandato e nella maggior parte dei casi, in realtà piuttosto cattiva pratica. Per esempio si potrebbe fare questo:
ExampleTask task = new ExampleTask() {
@Override
public void onPostExecute(String result) {
super.onPostExecute(result);
// Your code goes here
}
};
questo funzionerà altrettanto bene come l'attuazione di cui sopra con un'interfaccia ascoltatore separato, ma ci sono alcuni problemi con questo:
In primo luogo si può effettivamente rompere il ExampleTask
tutti insieme. Tutto si riduce alla chiamata super.onPostExecute()
qui sopra. Se come sviluppatore si sostituisce lo onPostExecute()
come sopra e si dimentica di includere la super chiamata o semplicemente di eliminarlo per qualsiasi motivo, il metodo originale onPostExecute()
nello ExampleTask
non verrà più chiamato. Ad esempio, l'intera implementazione listener con TaskListener
non funzionerà più poiché la chiamata al callback è implementata in onPostExecute()
. È inoltre possibile interrompere TaskListener
in molti altri modi influenzando inconsapevolmente o involontariamente lo stato di ExampleTask
in modo che non funzioni più.
Se si guarda a ciò che accade realmente quando si ridefinisce un metodo come questo, diventa molto più chiaro cosa sta succedendo.Sovrascrivendo onPostExecute()
si sta creando una nuova sottoclasse di ExampleTask
. Sarebbe la stessa cosa come fare questo:
public class AnotherExampleTask extends ExampleTask {
@Override
public void onPostExecute(String result) {
super.onPostExecute(result);
// Your code goes here
}
}
Tutto questo è solo nascosto dietro una caratteristica linguaggio chiamato classi anonime. Improvvisamente, un metodo come questo non sembra più così pulito e veloce, vero?
In sintesi:
- override un metodo come questo in realtà crea una nuova sottoclasse. Non stai semplicemente aggiungendo una richiamata, stai modificando il funzionamento di questa classe e puoi inconsapevolmente interrompere oh così tante cose.
- Errori di debug come questo possono essere molto più di un semplice dolore nella a **. Perché all'improvviso,
ExampleTask
potrebbe generare Exceptions
o semplicemente non funzionare più senza un motivo apparente, perché non hai mai effettivamente modificato il suo codice.
- Ogni classe deve fornire implementazioni di listener nei luoghi in cui è appropriata e prevista. Certo, puoi aggiungerli in seguito ignorando lo
onPostExecute()
ma è sempre molto pericoloso. Anche @flup con la sua reputazione 13k ha dimenticato di includere la chiamata super.onPostExecute()
nella sua risposta, immagina cosa potrebbe fare un altro sviluppatore non esperto!
- Una piccola astrazione non fa mai male a nessuno. Scrivere degli ascoltatori specifici potrebbe essere un po 'più codice, ma è una soluzione molto migliore. Il codice sarà più pulito, più leggibile e molto più gestibile. L'utilizzo di scorciatoie come la sostituzione di
onPostExecute()
essenzialmente sacrifica la qualità del codice per un po 'di comodità. Non è mai una buona idea e causerà solo problemi a lungo termine.
Non è così che lo fai^_ ^. Crei un thread in background utilizzando l'attività asincrona e il tuo codice, noto anche come httprequest, va nel metodo doInBackground() e tu ne definisci il returntype. Una volta terminata l'operazione in background, viene chiamato onPostExecute() nel quale si scrive il codice per gestire la risposta poiché ora si arriva ad aggiornare le viste e tutto. Esiste un metodo progressupdate che viene attivato quando viene raggiunto il progresso definito. Otterrò il collegamento della documentazione tra qualche istante – Rico
http://developer.android.com/reference/android/os/AsyncTask.html – Rico