Come posso eseguire il codice su un thread in background su Android?


131

Voglio che il codice venga eseguito continuamente in background. Non voglio farlo in un servizio. C'è un altro modo possibile?

Ho provato a chiamare la Threadclasse nel mio Activityma i miei Activityresti in background per qualche tempo e poi si ferma. La Threadclasse smette anche di funzionare.

class testThread implements Runnable {
        @Override
        public void run() {
            File file = new File( Environment.getExternalStorageDirectory(), "/BPCLTracker/gpsdata.txt" );
            int i = 0;

            RandomAccessFile in = null;

            try {
                in = new RandomAccessFile( file, "rw" );
            } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            }
//String line =null;
            while ( true ) {
                HttpEntity entity = null;
                try {
                    if ( isInternetOn() ) {
                        while ( ( line = in.readLine() ) != null ) {

                            HttpClient client = new DefaultHttpClient();
                            String url = "some url";
                            HttpPost request = new HttpPost( url );
                            StringEntity se = new StringEntity( line );
                            se.setContentEncoding( "UTF-8" );
                            se.setContentEncoding( new BasicHeader( HTTP.CONTENT_TYPE, "application/json" ) );
                            entity = se;
                            request.setEntity( entity );
                            HttpResponse response = client.execute( request );
                            entity = response.getEntity();
                            i++;
                        }
                        if ( ( line = in.readLine() ) == null && entity != null ) {
                            file.delete();
                            testThread t = new testThread();
                            Thread t1 = new Thread( t );
                            t1.start();
                        }


                    } else {
                        Thread.sleep( 60000 );
                    } // end of else

                } catch (NullPointerException e1) {
                    e1.printStackTrace();
                } catch (InterruptedException e2) {
                    e2.printStackTrace();
                } catch (IOException e1) {
// TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }// end of while
        }// end of run

    }

1
Ciao. Puoi per favore pubblicare un po 'di codice come esempio di quello che hai provato? Esistono diversi modi per eseguire il codice su un thread in background, ma è necessario ricordare che se si accede a qualsiasi componente dell'interfaccia utente, è necessario accedervi sul thread dell'interfaccia utente utilizzando il runOnUiThread()metodo
Alex Wiese,

3
C'è qualche motivo particolare per non utilizzare il servizio
DeltaCap019

questo non è così raccomandato. il funzionamento continuo scarica la batteria del dispositivo.
HelmiB,

Ho inviato il codice
user2082987

Ho provato ad usarlo nel servizio ma ha inviato lo stesso record più volte.
user2082987

Risposte:


379

Se hai bisogno di:

  1. esegue il codice su un thread in background

  2. eseguire il codice che NON tocca / aggiorna l'interfaccia utente

  3. eseguire il codice (breve) che richiederà al massimo alcuni secondi per essere completato

Quindi utilizzare il seguente modello pulito ed efficiente che utilizza AsyncTask:

AsyncTask.execute(new Runnable() {
   @Override
   public void run() {
      //TODO your background code
   }
});

10
Nota: richiede il livello API 11
friederbluemle il

9
Perché non dovresti usare quanto segue che è più leggero: new Thread (new Runnable () {@Override public void run () {// background background}}). Start ();
premiato

3
Esiste la possibilità che ciò causi perdita di memoria?
Hilfritz,

5
Una cosa da notare è che AsyncTask sono qeued. Se lo usi per un sacco di chiamate API del server, non verranno eseguite in parallelo.
Chase Roberts,


45

Ricorda Esecuzione in background, Esecuzione continua sono due attività diverse.

Per i processi in background a lungo termine, i thread non sono ottimali con Android. Tuttavia, ecco il codice e fallo a tuo rischio e pericolo ...

Ricorda che il servizio o il thread verranno eseguiti in background, ma la nostra attività deve essere attivata (richiamare più e più volte) per ottenere gli aggiornamenti, ovvero una volta completata l'attività è necessario richiamare la funzione per il prossimo aggiornamento.

Timer (trigger periodico), Allarme (trigger Timebase), Broadcast (trigger base eventi), ricorsione attiverà le nostre funzioni.

public static boolean isRecursionEnable = true;

void runInBackground() {
    if (!isRecursionEnable)
        // Handle not to start multiple parallel threads
        return;

    // isRecursionEnable = false; when u want to stop
    // on exception on thread make it true again  
    new Thread(new Runnable() {
        @Override
        public void run() {
            // DO your work here
            // get the data
            if (activity_is_not_in_background) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // update UI
                        runInBackground();
                    }
                });
            } else {
                runInBackground();
            }
        }
    }).start();
}

Utilizzo del servizio: se si avvia un servizio, verrà avviato, eseguirà l'attività e verrà terminato automaticamente. dopo l'esecuzione dell'attività. terminato potrebbe anche essere causato da un'eccezione o l'utente lo ha ucciso manualmente dalle impostazioni. START_STICKY (Sticky Service) è l'opzione fornita da Android che il servizio si riavvierà automaticamente al termine del servizio.

Ricordi la differenza di domanda tra multiprocessing e multithreading? Il servizio è un processo in background (proprio come l'attività senza interfaccia utente), allo stesso modo in cui si avvia il thread nell'attività per evitare il caricamento sul thread principale (thread attività), allo stesso modo in cui è necessario avviare thread (o attività asincrone) sul servizio per evitare il carico di servizio.

In una singola istruzione, se si desidera eseguire un'attività continua in background, è necessario avviare StickyService ed eseguire il thread nel servizio sulla base eventi


Consiglieresti questo metodo per eseguire un SignalStrengthListener personalizzato in background per una media di 20 minuti, mentre acquisisci i valori dall'ascoltatore una volta al secondo per aggiornare il thread dell'interfaccia utente? Qui è più contesto: stackoverflow.com/questions/36167719/...
JParks

Come viene eseguito nuovamente il processo se si imposta 'isRecursionEnable = true'? Quindi si chiama all'interno del metodo 'run' per 'runInBackground ()', come non inserire l'istruzione if all'inizio della funzione?
Topolino,

23

Voglio che il codice venga eseguito continuamente in background. Non voglio farlo in un servizio. C'è un altro modo possibile?

Molto probabilmente il meccanismo che stai cercando è AsyncTask. Ha designato direttamente per l'esecuzione del processo in background sul thread in background. Anche il suo principale vantaggio è che offre alcuni metodi che vengono eseguiti sul thread principale (UI) e rendono possibile aggiornare l'interfaccia utente se si desidera informare l'utente su alcuni progressi nell'attività o aggiornare l'interfaccia utente con i dati recuperati dal processo in background.

Se non sai come iniziare qui è un bel tutorial:

Nota: Inoltre v'è la possibilità di utilizzo IntentServicecon ResultReceiverche lavora bene.


@ user2082987 quindi l'hai provato?
Simon Dorociak,

questi parametri di asyncTask sono confusi
user2082987

AsyncTask è comunque solo un wrapper attorno al thread, quindi non risolve il problema di Android che uccide l'applicazione mentre è in background
Lassi Kinnunen

Ciao @LassiKinnunen Ho scritto questa risposta 5 anni fa. Ora tutto è cambiato e attualmente non sto usando AsyncTask perché la sua perdita di memoria non è sicura.
Simon Dorociak,

Sì, me ne rendo conto, ma la gente lo troverà comunque tramite google e ho visto così tanti commenti di persone che consigliano di utilizzare gli involucri di Google anche quando serve poco o nulla, mi dispiace. Per quanto riguarda la domanda originale se qualcuno sta cercando delle risposte nel 2018, crea un servizio e lancialo e contrassegnalo come in primo piano con una notifica se vuoi massimizzare le probabilità che non venga ucciso. L'effettivo processo di lunga durata può essere gestito con gestori o un thread separato. Non ti sei reso conto che sono riusciti a rendere davvero sicura la perdita di memoria?
Lassi Kinnunen,

16

Liner 3 semplice

Un modo semplice per farlo che ho trovato come commento di @awardak nella risposta di Brandon Rude :

new Thread( new Runnable() { @Override public void run() { 
  // Run whatever background code you want here.
} } ).start();

Non sono sicuro se, o come, sia meglio dell'uso AsyncTask.executema sembra funzionare per noi. Eventuali commenti sulla differenza sarebbero apprezzati.

Grazie, @awardak !


usiamo il metodo handler.post () per riportarlo sul thread principale all'interno del metodo run di Thread.
androidXP,

2

Un'alternativa a AsyncTask è robospice. https://github.com/octo-online/robospice .

Alcune delle caratteristiche di Robospice.

1. esegue richieste di rete in modo asincrono (in un servizio Android in background) (es: richieste REST utilizzando Spring Android). Notifica l'app, sul thread dell'interfaccia utente, quando il risultato è pronto.

2.è fortemente tipizzato! Fai le tue richieste utilizzando POJO e ottieni POJO come risultati della richiesta.

3. non imporre alcun vincolo né ai POJO utilizzati per le richieste né alle classi di attività utilizzate nei progetti.

4.caches risultati (in Json con Jackson e Gson, o Xml, o file di testo piatti o file binari, anche usando ORM Lite).

5. notifica le tue attività (o qualsiasi altro contesto) del risultato della richiesta di rete se e solo se sono ancora vivi

6. nessuna perdita di memoria, come i caricatori Android, a differenza di Android AsyncTasks notifica le tue attività sul loro thread dell'interfaccia utente.

7. utilizza un modello di gestione delle eccezioni semplice ma robusto.

Campioni per cominciare. https://github.com/octo-online/RoboSpice-samples .

Un esempio di robospice su https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result .


Come archiviare un array ottenuto dalla rete su SQLite? Fondamentalmente vorrei: ottenere i dati dalla rete E salvarli nel mio SQLite - entrambi in thread in background, quindi ricevere la mia interfaccia utente per aggiornare ListView. Di solito lo faccio con IntentService, ma RoboSpice sta scrivendo meno.
Anno

@yar è possibile utilizzare un servizio intent se si tratta di un'operazione di lunga durata. Inoltre puoi usare asynctask ma solo se è di breve durata. Puoi creare una discussione e fare tutte le tue cose lì. Non uso Robospice da molto tempo ormai. Ci sono altre biblioteche di rete come il volley ...
Raghunandan,

Ok grazie. Ho pensato di usare Robospice, ma sembra che non sia troppo buono (flessibile) per le mie esigenze. Uso IntentService da molto tempo con successo.
Anno

2
class Background implements Runnable {
    private CountDownLatch latch = new CountDownLatch(1);
    private  Handler handler;

    Background() {
        Thread thread = new Thread(this);
        thread.start();
        try {
            latch.await();
        } catch (InterruptedException e) {
           /// e.printStackTrace();
        }
    }

    @Override
    public void run() {
        Looper.prepare();
        handler = new Handler();
        latch.countDown();
        Looper.loop();
    }

    public Handler getHandler() {
        return handler;
    }
}

5
Benvenuto in StackOverflow. Le risposte con solo codice in esse tendono ad essere contrassegnate per la cancellazione in quanto sono "di bassa qualità". Si prega di leggere la sezione di aiuto per rispondere alle domande, quindi prendere in considerazione l'aggiunta di alcuni commenti alla risposta.
Graham

0

Se hai bisogno di eseguire il thread predioticmente con codici diversi, ecco un esempio:

Ascoltatore:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

Classe discussione

public class ESLThread extends AsyncTask<Void, Void, List> {


    private ESLThreadListener mListener;

    public ESLThread() {

        if(mListener != null){

            mListener.onBackground();
        }
    }

    @Override
    protected List doInBackground(Void... params) {

        if(mListener != null){

            List list = mListener.onBackground();

            return list;
        }

        return null;
    }

    @Override
    protected void onPostExecute(List t) {
        if(mListener != null){

            if ( t != null) {
                mListener.onPostExecute(t);
            }
        }

    }


    public void setListener(ESLThreadListener mListener){

        this.mListener = mListener;
    }
}

Esegui codici diversi:

  ESLThread thread = new ESLThread();
                        thread.setListener(new ESLThreadListener() {
                            @Override
                            public List onBackground() {
                                List<EntityShoppingListItems>  data = RoomDB.getDatabase(context).sliDAO().getSL(fId);

                                return data;

                            }

                            @Override
                            public void onPostExecute(List t) {

                                List<EntityShoppingListItems> data = (List<EntityShoppingListItems>)t;
                                adapter.setList(data);
                            }
                        });

                        thread.execute();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.