Domanda

Ho lavorato con AsyncTasks in Android e ho a che fare con un problema.

fare un semplice esempio, un'attività con un'AsyncTask. Il compito sullo sfondo non fa nulla di spettacolare, solo dorme per 8 secondi.

Al termine del AsyncTask nel OnPostExecute () Metodo io sono solo la fissazione di uno stato del pulsante visibilità a View.VISIBLE, solo per verificare i miei risultati.

Ora, questo funziona alla grande finché l'utente non decide di cambiare il suo orientamento cellulari durante l'AsyncTask sta lavorando (all'interno della finestra del sonno 8 secondi).

Capisco il ciclo di vita di attività Android e so che l'attività viene distrutto e ricreato.

Questo è dove il problema entra in gioco. L'AsyncTask si riferisce a un pulsante e apparentemente contiene un riferimento al contesto che ha iniziato l'AsyncTask in primo luogo.

mi aspetterei, che questo vecchio contesto (in quanto l'utente ha causato un cambiamento di orientamento) per diventare o nulla e l'AsyncTask di gettare un NPE per il riferimento al pulsante che sta cercando di rendere visibile.

Al contrario, non NPE viene lanciata, l'AsyncTask pensa che il riferimento pulsante non è nullo, imposta su visibile. Il risultato? Nulla sta accadendo sullo schermo!

Aggiorna Ho affrontato questo mantenendo un WeakReference all'attività e commutazione quando un cambiamento di configurazione avviene. Questo è ingombrante.

Ecco il codice:

public class Main extends Activity {

    private Button mButton = null;
    private Button mTestButton = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mButton = (Button) findViewById(R.id.btnStart);
        mButton.setOnClickListener(new OnClickListener () {
            @Override
            public void onClick(View v) {
                new taskDoSomething().execute(0l);
            }
        });
        mTestButton = (Button) findViewById(R.id.btnTest);   
    }

    private class TaskDoSomething extends AsyncTask<Long, Integer, Integer> 
    {
        @Override
        protected Integer doInBackground(Long... params) {
            Log.i("LOGGER", "Starting...");
            try {
                Thread.sleep(8000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 0;
        }

        @Override
        protected void onPostExecute(Integer result) {
            Log.i("LOGGER", "...Done");
            mTestButton.setVisibility(View.VISIBLE);
        }
    }
}

Prova sua esecuzione e mentre l'AsyncTask sta lavorando cambiare l'orientamento telefoni.

È stato utile?

Soluzione

AsyncTask non è progettato per essere riutilizzato dopo un'attività è stato strappato e riavviato. L'oggetto Handler interna diventa stantio, proprio come lei ha affermato. Nell'esempio Mensole di Romain Guy, lui semplice annulla qualsiasi attualmente in esecuzione AsyncTask di e quindi riavvia il cambiamento di nuovi post-orientamento.

E 'possibile consegnare il vostro filo alla nuova attività, ma aggiunge un sacco di tubature. Non si può in generale d'accordo sul modo di fare questo, ma si può leggere il mio metodo qui: http://foo.jasonhudgins.com/2010/03/simple-progressbar-tutorial.html

Altri suggerimenti

Se avete solo bisogno di un contesto e non verrà utilizzato per le cose ui si può semplicemente passare l'ApplicationContext al AsyncTask.You spesso bisogno del contesto per le risorse di sistema, per esempio.

Non cercare di aggiornare l'interfaccia utente da un AsyncTask e cercare di evitare la gestione di configurazione te cambia come si può ottenere disordinato. Per aggiornare l'interfaccia utente è possibile registrare un ricevitore broadcast e inviare un broadcast.

Si dovrebbe anche avere l'AsyncTask come una classe pubblica separato dalla attività di cui sopra, si fa la prova di un molto più facile. Purtroppo la programmazione Android rafforza spesso cattive pratiche e gli esempi ufficiali non stanno aiutando.

Questo è il tipo di cosa che mi porta a evitare sempre la mia attività venga distrutto / ricreato sul cambiamento di orientamento.

Per fare in modo aggiungere questo al tuo tag <Activity> nel file manifest:

android:configChanges="orientation|keyboardHidden" 

e sovrascrivere onConfigurationChanged nella classe di attività:

@Override
public void onConfigurationChanged(final Configuration newConfig)
{
    // Ignore orientation change to keep activity from restarting
    super.onConfigurationChanged(newConfig);
}

Per evitare questo è possibile utilizzare la risposta GIVIN qui: https://stackoverflow.com/a/2124731/327011

Ma se avete bisogno di distruggere l'attività (diversi layout per verticale e orizzontale) è possibile effettuare l'AsyncTask una classe pubblica (leggi qui il motivo per cui non dovrebbe essere privato Android: raccomandazioni AsyncTask:? classe private o public class ) e quindi creare un metodo setActivity per impostare il riferimento alla corrente attività ogniqualvolta viene distrutto / creato.

È possibile vedere un esempio qui: Android AsyncTask in classe esterna

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top