Wie kann ich Code in einem Hintergrund-Thread unter Android ausführen?

131

Ich möchte, dass Code kontinuierlich im Hintergrund ausgeführt wird. Ich möchte es nicht in einem Dienst tun. Ist ein anderer Weg möglich?

Ich habe versucht, die ThreadKlasse in meinem anzurufen, Activityaber meine Activitybleibt für einige Zeit im Hintergrund und dann hört es auf. Die ThreadKlasse hört auch auf zu arbeiten.

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

    }
user2082987
quelle
1
Hallo. Können Sie bitte einen Code als Beispiel für das, was Sie versucht haben, posten? Es gibt verschiedene Möglichkeiten, Code in einem Hintergrundthread auszuführen. Wenn Sie jedoch auf UI-Komponenten zugreifen, müssen Sie mithilfe der runOnUiThread()Methode auf diese im UI-Thread zugreifen .
Alex Wiese
3
Gibt es einen bestimmten Grund für die
Nichtbenutzung
Dies wird nicht so empfohlen. Wenn Sie kontinuierlich laufen, wird die Batterie des Geräts entladen.
HelmiB
Ich habe den Code gesendet.
user2082987
Ich habe versucht, es im Dienst zu verwenden, aber es sendet denselben Datensatz mehrmals.
user2082987

Antworten:

379

Wenn du musst:

  1. Code auf einem Hintergrund-Thread ausführen

  2. Führen Sie Code aus, der die Benutzeroberfläche NICHT berührt / aktualisiert

  3. Führen Sie (Kurz-) Code aus, dessen Fertigstellung höchstens einige Sekunden dauert

Verwenden Sie dann das folgende saubere und effiziente Muster, das AsyncTask verwendet:

AsyncTask.execute(new Runnable() {
   @Override
   public void run() {
      //TODO your background code
   }
});
Brandon unhöflich
quelle
10
Hinweis: Erfordert API Level 11
friederbluemle
9
Warum würden Sie nicht Folgendes verwenden, das leichter ist: new Thread (new Runnable () {@Override public void run () {// Hintergrundcode}}). Start ();
Awardak
3
Gibt es die Möglichkeit, dass dies zu einem Speicherverlust führt?
Hilfritz
5
Zu beachten ist, dass AsyncTasks ausgeführt werden. Wenn Sie dies für eine Reihe von Server-API-Aufrufen verwenden, werden diese nicht parallel ausgeführt.
Chase Roberts
4
Hinweis: AsyncTask wurde in API Level R
Sandre
45

Denken Sie daran, Hintergrund laufen, kontinuierlich laufen sind zwei verschiedene Aufgaben.

Für langfristige Hintergrundprozesse sind Threads mit Android nicht optimal. Hier ist jedoch der Code und Sie tun dies auf eigenes Risiko ...

Denken Sie daran, dass Service oder Thread im Hintergrund ausgeführt werden, aber unsere Aufgabe muss ausgelöst werden (immer wieder aufrufen), um Aktualisierungen zu erhalten. Wenn die Aufgabe abgeschlossen ist, müssen wir die Funktion für die nächste Aktualisierung zurückrufen.

Timer (periodischer Trigger), Alarm (Timebase-Trigger), Broadcast (Event Base Trigger) und Rekursion wecken unsere Funktionen.

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();
}

Verwenden des Dienstes: Wenn Sie einen Dienst starten, wird dieser gestartet, die Aufgabe ausgeführt und sich selbst beendet. nach der Ausführung der Aufgabe. Das Beenden kann auch durch eine Ausnahme verursacht werden, oder der Benutzer hat es manuell über die Einstellungen beendet. START_STICKY (Sticky Service) ist die von Android angegebene Option, dass der Dienst sich selbst neu startet, wenn der Dienst beendet wird.

Erinnern Sie sich an den Unterschied zwischen Multiprocessing und Multithreading? Der Dienst ist ein Hintergrundprozess (genau wie eine Aktivität ohne Benutzeroberfläche). So wie Sie einen Thread in der Aktivität starten, um das Laden des Hauptthreads (Aktivitätsthread) zu vermeiden, müssen Sie auch Threads (oder asynchrone Aufgaben) für den Dienst starten um eine Belastung des Dienstes zu vermeiden.

Wenn Sie in einer einzelnen Anweisung eine Aufgabe zum Ausführen eines Hintergrunds ausführen möchten, müssen Sie einen StickyService starten und den Thread im Service auf Ereignisbasis ausführen

Sandeep P.
quelle
Würden Sie diese Methode empfehlen, um einen benutzerdefinierten SignalStrengthListener durchschnittlich 20 Minuten lang im Hintergrund auszuführen und gleichzeitig einmal pro Sekunde Werte vom Listener abzurufen, um den UI-Thread zu aktualisieren? Hier ist mehr Kontext: stackoverflow.com/questions/36167719/…
JParks
Wie wird der Prozess erneut ausgeführt, wenn Sie 'isRecursionEnable = true' festlegen? Sie rufen dann die 'run'-Methode für' runInBackground () 'auf. Wie würde sie nicht die if-Anweisung am Anfang der Funktion eingeben?
Mickey
23

Ich möchte, dass Code kontinuierlich im Hintergrund ausgeführt wird. Ich möchte es nicht in einem Dienst tun. Ist ein anderer Weg möglich?

Der wahrscheinlichste Mechanismus, den Sie suchen, ist AsyncTask. Es ist direkt für die Durchführung eines Hintergrundprozesses für einen Hintergrund-Thread vorgesehen. Der Hauptvorteil besteht auch darin, dass einige Methoden angeboten werden, die auf dem Hauptthread (UI) ausgeführt werden und die Aktualisierung Ihrer Benutzeroberfläche ermöglichen, wenn Sie den Benutzer über Fortschritte bei der Aufgabe informieren oder die Benutzeroberfläche mit Daten aktualisieren möchten, die aus dem Hintergrundprozess abgerufen wurden.

Wenn Sie nicht wissen, wie Sie hier anfangen sollen, finden Sie hier ein nettes Tutorial:

Hinweis: Auch besteht die Möglichkeit , auf den Einsatz IntentServicemit ResultReceiver, die auch funktioniert.

Simon Dorociak
quelle
@ user2082987 Also hast du es versucht?
Simon Dorociak
Diese Parameter von asyncTask sind verwirrend
user2082987
AsyncTask ist sowieso nur ein Wrapper um den Thread, daher löst es nicht das Problem, dass Android die Anwendung im Hintergrund beendet
Lassi Kinnunen
Hi @LassiKinnunen Ich habe diese Antwort vor 5 Jahren geschrieben. Jetzt ist alles geändert und ich verwende AsyncTask derzeit nicht, da der Speicherverlust nicht sicher ist.
Simon Dorociak
Ja, das ist mir klar, aber die Leute werden dies immer noch über Google finden, und ich habe so viele Kommentare von Leuten gesehen, die die Verwendung der Google-Wrapper empfehlen, auch wenn sie wenig bis gar keinen Zweck erfüllen, sorry. Wenn für die ursprüngliche Frage 2018 jemand nach Antworten sucht, erstellen Sie einen Dienst, starten Sie ihn und markieren Sie ihn als Vordergrund mit einer Benachrichtigung, wenn Sie die Wahrscheinlichkeit maximieren möchten, dass er nicht getötet wird. Der eigentliche Prozess mit langer Laufzeit kann mit Handlern oder einem separaten Thread abgewickelt werden. Wussten Sie nicht, dass sie es tatsächlich geschafft haben, den Speicher nicht sicher zu machen?
Lassi Kinnunen
16

Einfacher 3-Liner

Ein einfacher Weg, dies zu tun, den ich als Kommentar von @awardak in Brandon Rudes Antwort gefunden habe :

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

Ich bin mir nicht sicher, ob oder wie dies besser ist als zu verwenden, AsyncTask.executeaber es scheint für uns zu funktionieren. Kommentare zum Unterschied sind willkommen.

Danke, @awardak !

Joshua Pinter
quelle
Wir verwenden die Methode handler.post (), um sie wieder im Hauptthread innerhalb der Ausführungsmethode von Thread zu veröffentlichen.
androidXP
2

Eine Alternative zu AsyncTask ist Robospice. https://github.com/octo-online/robospice .

Einige der Merkmale von Robospice.

1. führt asynchrone (in einem AndroidService-Hintergrund) Netzwerkanforderungen aus (z. B. REST-Anforderungen mit Spring Android). Benachrichtigen Sie Ihre App im UI-Thread, wenn das Ergebnis fertig ist.

2.ist stark getippt! Sie stellen Ihre Anfragen mit POJOs und erhalten POJOs als Anforderungsergebnisse.

3.Erzwingen Sie keine Einschränkungen, weder für POJOs, die für Anforderungen verwendet werden, noch für Aktivitätsklassen, die Sie in Ihren Projekten verwenden.

4.caches Ergebnisse (in Json mit Jackson und Gson oder Xml oder Flat-Text-Dateien oder Binärdateien, sogar mit ORM Lite).

5. Benachrichtigt Ihre Aktivitäten (oder einen anderen Kontext) über das Ergebnis der Netzwerkanforderung, wenn und nur wenn sie noch aktiv sind

6. Kein Android-Verlust, wie bei Android Loadern, im Gegensatz zu Android AsyncTasks benachrichtigt Ihre Aktivitäten in ihrem UI-Thread.

7. verwendet ein einfaches, aber robustes Ausnahmebehandlungsmodell.

Beispiele für den Anfang. https://github.com/octo-online/RoboSpice-samples .

Ein Beispiel für Robospice unter https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result .

Raghunandan
quelle
Wie speichere ich ein vom Netzwerk erhaltenes Array in SQLite? Grundsätzlich möchte ich: Daten aus dem Netzwerk abrufen UND auf meiner SQLite speichern - beide im Hintergrund-Thread, und dann meine Benutzeroberfläche benachrichtigen lassen, um ListView zu aktualisieren. Normalerweise mache ich das mit IntentService, aber RoboSpice tippt weniger.
Yar
@yar Sie können einen Intent-Service verwenden, wenn es sich um einen lang laufenden Vorgang handelt. Sie können auch Asynctask verwenden, aber nur für kurze Zeit. Sie können einen Thread erstellen und dort all Ihre Sachen machen. Ich habe Robospice schon lange nicht mehr benutzt. Es gibt andere Netzwerkbibliotheken wie Volley ...
Raghunandan
OK danke. Ich habe überlegt, Robospice zu verwenden, aber es sieht so aus, als wäre es nicht zu gut (flexibel) für meine Bedürfnisse. Ich benutze IntentService schon lange mit Erfolg.
Yar
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;
    }
}
Geno Papashvili
quelle
5
Willkommen bei StackOverflow. Antworten, die nur Code enthalten, werden in der Regel zum Löschen markiert, da sie von "geringer Qualität" sind. Bitte lesen Sie den Hilfeabschnitt zur Beantwortung von Fragen und fügen Sie Ihrer Antwort einen Kommentar hinzu.
Graham
0

Wenn Sie einen Thread prädiotisch mit verschiedenen Codes ausführen müssen, ist hier ein Beispiel:

Hörer:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

Thread-Klasse

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;
    }
}

Führen Sie verschiedene Codes aus:

  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();
Ucdemir
quelle