https://developer.android.com/guide/components/processes-and-threads?hl=JA (2019/8/24)
Multithread-Zusammenfassung finden Sie hier
Wenn die Anwendung eine Komponente ausführt, startet das Android-System einen Linux-Prozess für einen einzelnen Thread.
Komponente
Aktivität / Dienst / Inhaltsanbieter / Rundfunkempfänger
Aktivitäten, Dienste und Rundfunkempfänger werden mit Intent (asynchrone Nachricht) aktiviert.
Prozess / Linux-Prozess
Ein Programm, das unter Linux ausgeführt wird. </ font>
Standardmäßig werden alle Komponenten derselben Anwendung im selben Prozess und Thread (Hauptthread) ausgeführt.
Wenn eine App-Komponente gestartet wird und ein anderer Prozess vorhanden ist, startet die Komponente innerhalb dieses Prozesses und verwendet denselben Ausführungsthread.
Sie können jedoch verschiedene Komponenten in Ihrer Anwendung so anpassen, dass sie in verschiedenen Prozessen ausgeführt werden, und Sie können für jeden Prozess separate Threads erstellen.
Wenn Sie den Prozess verwalten möchten, zu dem eine bestimmte Komponente gehört, geben Sie ihn in der Manifestdatei an.
Manifest-Einträge für jeden Typ von Komponentenelement (\ <Aktivität> / \
Abhängig von den Einstellungen für ** android: process ** kann jede Komponente in einem eigenen Prozess ausgeführt werden, einige Komponenten können denselben Prozess gemeinsam nutzen oder verschiedene Prozesse können verwendet werden. Sie können auch Komponenten verschiedener Anwendungen im selben Prozess ausführen lassen (die Apps müssen dieselbe Linux-Benutzer-ID verwenden und mit demselben Zertifikat signiert sein).
Das Element ** \
Das Android-System kann Prozesse herunterfahren und Anwendungskomponenten zerstören. Bei der Entscheidung über den zu verwerfenden Prozess ermittelt das System die Kandidaten anhand der relativen Nachfrage. Später erkläre ich die Regeln, die den Prozess des Verwerfens bestimmen.
Basierend auf den im Prozess ausgeführten Komponenten und dem Status der Komponenten positioniert das Android-System jeden Prozess in einer "Prioritätshierarchie" und versucht, ihn aus weniger wichtigen Prozessen zu entfernen und Systemressourcen wiederherzustellen.
Wenn Ihnen der Speicher oder die Ressourcen ausgehen, müssen Sie den Vordergrundprozess beenden.
Ein Prozess, der keine Vordergrundkomponente ist, aber den Inhalt des Benachrichtigungsbereichs für den Benutzer beeinflussen kann. Es wird als sichtbarer Prozess angesehen, wenn:
Obwohl nicht im Vordergrund, ist es der Host der Aktivität </ font>, die dem Benutzer angezeigt wird ( onPause () </ font> > Die Methode wurde aufgerufen).
Sie hosten einen Service </ font>, der an eine sichtbare (oder Vordergrund-) Aktivität gebunden ist.
Sichtbare Prozesse sind von großer Bedeutung und werden nur beendet, wenn der Vordergrundprozess weiter ausgeführt werden muss.
Der Prozess zum Ausführen eines Dienstes, der mit der Methode startService () </ font> gestartet wurde und nicht in die beiden oben genannten Kategorien fällt. Zusammen mit allen Vordergrund- und sichtbaren Prozessen sind sie nur dann Kandidaten für das Töten, wenn nicht genügend Speicher vorhanden ist, um sie fortzusetzen.
Ein Prozess, der eine Aktivität enthält, die für den Benutzer nicht sichtbar ist (die Methode onStop () </ font> wurde aufgerufen). Es kann jederzeit beendet werden, um den Speicher wiederherzustellen. Hintergrunddienste werden in der LRU-Liste (Least Recent Used) verwaltet und vom ältesten Vorgang beendet.
Wenn die Aktivität die Lebenszyklusmethode genau implementiert und ihren aktuellen Status beibehält, wird der visuelle Status wiederhergestellt, wenn sie fortgesetzt wird, auch wenn sie beendet wird.
Ein Prozess ohne aktive Anwendungskomponenten. Dieser Prozess wird zum Zwischenspeichern des Prozesses beibehalten und startet schnell die nächste Komponente. Dieser Prozess wird häufig abgebrochen.
Positionieren Sie den Prozess für Komponenten mit mehreren Wichtigkeiten im wichtigsten Rang. Außerdem kann ein Prozess, der für einen anderen Prozess ausgeführt wird, nicht unter dem abhängigen / gebundenen Prozess positioniert werden (wenn er darunter positioniert ist, kann er nicht ausgeführt werden, wenn der abhängige Prozess zerstört wird. ).
Dienste sind wichtiger als der Hintergrund, und für Aktivitäten mit langer Laufzeit (insbesondere wenn der Prozess länger als die Aktivität dauert) sollte der Prozess den Dienst verwenden, anstatt einen Arbeitsthread zu erstellen. Wenn Sie beispielsweise ein Bild ins Web hochladen, verwendet die Aktivität einen Dienst, mit dem der Benutzer beim Verlassen der Aktivität im Hintergrund weiterarbeiten kann. Sogar Rundfunkempfänger sollten Dienste nutzen, anstatt sie über einen längeren Zeitraum von Threads verarbeiten zu lassen.
Wenn die Anwendung gestartet wird, erstellt das System einen Hauptthread zum Ausführen der Anwendung. Der Haupt-Thread ist sehr wichtig, um für das Senden von Ereignissen (einschließlich Zeichenereignissen) an die entsprechenden UI-Widgets verantwortlich zu sein.
Der Hauptthread ermöglicht der App auch die Interaktion mit Komponenten im Android UI Toolkit (Komponenten im Paket android.widget / android.view </ font>). Daher wird der Hauptthread auch als UI-Thread bezeichnet (in einigen besonderen Fällen ist der Hauptthread nicht der UI-Thread).
Für jede Instanz der Komponente wird kein separater Thread erstellt. Alle Komponenten, die im selben Prozess ausgeführt werden, werden im UI-Thread instanziiert, und das System ruft die vom UI-Thread gesendeten Komponenten auf. Methoden, die auf Systemrückrufe reagieren, werden immer im UI-Thread des Prozesses ausgeführt.
(Beispiel: Wenn der Benutzer eine Schaltfläche auf dem Bildschirm berührt, sendet der UI-Thread der App ein Berührungsereignis an das Widget, das Widget legt den Berührungsstatus fest und der UI-Thread sendet eine Ungültigkeitsanforderung an die Ereigniswarteschlange. Empfängt eine Anfrage aus der Warteschlange und benachrichtigt das Widget über das Zeichnen.
Wenn alles in einem UI-Thread erledigt ist, kann das Ausführen zeitaufwändiger Vorgänge die gesamte UI blockieren. Außerdem ist das Android UI Toolkit nicht threadsicher, sodass Sie nicht über Worker-Threads mit der Benutzeroberfläche interagieren können. Alle Vorgänge müssen über den UI-Thread ausgeführt werden. Daher gibt es zwei Regeln für das Android-Single-Thread-Modell.
1. Blockieren Sie keine UI-Threads 2. Greifen Sie nur von dem UI-Thread </ strong> auf das Android-UI-Toolkit zu Zugriffsmethoden werden nicht vom UI-Thread bereitgestellt. ( View kann nur von dem Thread aus bedient werden, der die View </ font> </ strong> erstellt hat.)
Der Arbeitsthread ist ein Thread ohne Benutzeroberfläche und führt die empfangene Verarbeitungsanforderung aus (auch als backgroundThread bezeichnet). Der Arbeitsthread verhält sich so, als würde er warten, auch wenn keine Verarbeitungsanforderung vorliegt, und führt ihn aus, wenn er die Verarbeitungsanforderung empfängt. Abhängig vom Verarbeitungsinhalt können mehrere Arbeitsthreads vorhanden sein, und der Speicherort kann als Thread-Pool bezeichnet werden. </ font>
Das Single-Threaded-Modell sollte keine UI-Threads blockieren, um die Reaktionsfähigkeit der UI der Anwendung zu gewährleisten. Vorgänge, die nicht sofort ausgeführt werden müssen, werden in einem separaten Thread (Arbeitsthread (Hintergrundthread)) ausgeführt.
<Referenz: Regelverletzungscode </ font> >>
python
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork("http://example.com/image.png ");
mImageView.setImageBitmap(b);
}
}).start();
}
Der Versuch, ImageView </ font> im Worker-Thread anstelle des UI-Threads zu ändern, verstößt gegen Regel 2 (auf das Android UI Toolkit wird nur über den UI-Thread zugegriffen).
<Referenz: Geänderter Code von View.post (ausführbar) </ font> >> Implementieren Sie View.post (Runnable), um den Thread sicher zu machen
python
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap bitmap =
loadImageFromNetwork("http://example.com/image.png ");
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
Netzwerkoperationen werden in einem separaten Thread (loadImageFromNetwork ()) ausgeführt. ImageView wird über den UI-Thread (mImageView.post (new Runnable () {})) betrieben.
Die Methode zur Verwendung von View.post zum Betreiben einer Ansicht über einen UI-Thread ist schwierig zu pflegen, da der Vorgang kompliziert wird. Um komplexe Interaktionen mit Worker-Threads zu verarbeiten, können Sie Handler in Worker-Threads verwenden, um von UI-Threads übermittelte Nachrichten zu verarbeiten. Die empfohlene Methode besteht jedoch darin, die AsyncTask-Klasse zu erweitern. Vereinfacht die Ausführung von Worker-Thread-Aufgaben, die mit der Benutzeroberfläche interagieren.
AsyncTask führt eine asynchrone Verarbeitung durch. Sie müssen den Thread oder Handler nicht selbst behandeln, er blockiert den Betrieb des Worker-Threads und liefert das Ergebnis an den UI-Thread.
Um AsyncTask zu verwenden, unterordnen Sie AsyncTask </ font> und führen Sie es in einem Pool von Hintergrundthreads aus. doInBackground () </ font> Rückruf Implementieren Sie die Methode.
Implementieren Sie onPostExecute () </ font>, um das Ergebnis in der Benutzeroberfläche wiederzugeben. onPostExecute () </ font> liefert das Ergebnis von doInBackground () </ font> an die Benutzeroberfläche und aktualisiert den UI-Thread, also die Benutzeroberfläche Kann sicher aktualisiert werden. Der UI-Thread ruft execute () </ font> auf, um die Aufgabe auszuführen.
<Referenz: Schreiben Sie den obigen Code mit AsycnTask neu>
public void onClick(View v){
new DownloadImageTask().execute("http://example.com/image.png ");
}
private class DownloadImageTask extends AsyncTask<String,Void,Bitmap>{
//Das System ruft die folgende Methode auf, um sie im Arbeitsthread zu verarbeiten:
// AsyncTask.execue()Liefern Sie die von der Methode übergebenen Parameter
protected Bitmap doInBackground(String... urls){
return loadImageFromNetwork(urls[0]);
}
//Das System ruft die folgende Methode zur Verarbeitung im UI-Thread auf
// doInBackground()Liefern Sie das Ergebnis an die Methode
protected void onPostExecute(Bitmap result){
mImageView.setImageBitmap(result);
}
}
Die Arbeit des Worker-Threads und die Arbeit des UI-Threads sind getrennt, sodass die UI sicher und der Code einfach ist.
So funktioniert AsyncTask
--Generics kann verwendet werden, um den Parametertyp, den Fortschrittswert und den Endwert der Aufgabe anzugeben
COUSION: Probleme, die bei der Verwendung von Arbeitsthreads auftreten können Änderungen an den Laufzeiteinstellungen, z. B. beim Drehen des Bildschirms, können dazu führen, dass die Aktivität unerwartet neu gestartet wird und der Arbeitsthread zerstört wird. Im folgenden Beispiel-Quellcode der App erfahren Sie, wie Sie die Aufgabe während des Neustarts beibehalten und die Aufgabe ordnungsgemäß abbrechen, wenn die Aktivität zerstört wird.> Https://code.google.com/archive/p/ Regale / |
Wenn die implementierte Methode von mehreren Threads aufgerufen wird, erstellen Sie die Methode so, dass sie threadsicher ist.
Fern aufgerufene Methoden, z. B. von primär gebundenen Diensten, können von mehreren Threads aus aufgerufen werden. Beim Aufruf von mehreren Threads lauten die Threads, die die remote aufgerufene Methode ausführen, wie folgt.
Beispielsweise wird die onBind () </ font> -Methode des Dienstes von einem UI-Thread im Prozess des Dienstes aufgerufen, während onBind () Die in dem von </ font> zurückgegebenen Objekt implementierten Methoden (z. B. die Unterklasse, die die RPC-Methode implementiert) werden von Threads im Thread-Pool aufgerufen. Da der Dienst mehrere Clients haben kann, können mehrere Thread-Pools gleichzeitig dieselbe IBinder-Methode </ font> ausführen. Daher muss die IBinder-Methode implementiert werden, um threadsicher zu sein. ..
RPC-Methode: Die Methode wird lokal aufgerufen, remote ausgeführt (in einem anderen Prozess) und das Ergebnis an den Aufrufer zurückgegeben. </ font>
Ebenso können Inhaltsanbieter Datenanforderungen empfangen, die von anderen Prozessen gesendet wurden. Die Klassen ContentResolver </ font> und ContentProvider </ font> verdecken die Verwaltung der Kommunikation zwischen Prozessen. Die ContentProvider </ font> -Methode ( query (), insert (), delete (), updater (), getType) antwortet jedoch auf diese Anforderungen. () </ Font>) wird als Thread-Pool im Prozess des Inhaltsanbieters und nicht als UI-Thread des Prozesses bezeichnet. Diese Methoden können von mehreren Methoden gleichzeitig aufgerufen werden und müssen implementiert werden, um threadsicher zu sein.
Steuern (Synchronisieren), Arbitrieren oder Steuern anderer Threads, während ein Thread ausgeführt wird, um Thread-Konflikte zu vermeiden (Beziehungen, in denen mehrere Threads gleichzeitig auf dieselbe Klasse, Methode oder Variable zugreifen und Daten zerstören). Exklusive Kontrolle) und machen Sie die Klasse oder Methode auch dann sicher, wenn der gleichzeitige Zugriff von mehreren Threads aus erfolgt.
Android verfügt über einen Mechanismus für die Kommunikation zwischen Prozessen mithilfe eines Remote Procedure Call (RPC), bei dem eine Methode von einer Aktivität oder einer anderen Anwendungskomponente aufgerufen, dann remote ausgeführt wird (ein anderer Prozess) und das Ergebnis aufgerufen wird. Kehrt zu zurück. Da das System für die Verarbeitung der Kommunikation zwischen Prozessen verantwortlich ist, muss der Entwickler nur die RPC-Programmierschnittstelle definieren und implementieren. Für die IPC-Ausführung muss die App mit bindService () </ font> an den Dienst gebunden sein. Weitere Informationen> https://developer.android.com/guide/components/services.html?hl=JA
Handle Mit dem Handler können Sie Message </ font> und ausführbare Objekte (z. B. Runnable) erstellen, die der MessageQueue </ font> des Threads zugeordnet sind. Sie können es senden und verarbeiten.
Eine Instanz von Handler ist einem einzelnen Thread und der Nachrichtenwarteschlange dieses Threads zugeordnet.
Wenn Sie einen neuen Handler erstellen, wird der Handler dem erzeugten Thread und seiner Nachrichtenwarteschlange zugewiesen. Der Handler kann dann die Nachricht und die ausführbare Nachrichtenwarteschlange zustellen und sie aus der Warteschlange entfernen und die Nachricht ausführen.
■ Post Version post(Runnable)/postAtTime(java.lang.Runnable,long)/postDelayed(Runnable,Object,long)
■ Send Message Version sendEmptyMessege(int)/sendMessage(Message)/sendMessageAtTime(Message,long)/sendmessageDelayed(Message,long)
Die Post-Version stellt eine ausführbare Datei in die Warteschlange, wenn sie empfangen wird.
Die SendMassege-Version stellt Nachrichtenobjekte in die Warteschlange. Das Nachrichtenobjekt enthält eine Sammlung von Daten, die in der HandleMessage (Message) -Methode des Handlers verwendet werden. (HandleMessage (Massage) implementiert eine Unterklasse von Handler)
Durch das Posten oder Senden eines Handlers können Sie ihn verarbeiten, sobald die Nachrichtenwarteschlange bereit ist. Sie können auch die Verzögerung der Verarbeitung und die Ausführungszeit angeben.
Später werde ich die Implementierung von Timing-Operationen wie Timeout-Verarbeitung und Ticks (timer-like) erläutern.
Wenn die Anwendung ausgeführt wird, wird der Hauptthread zu einem dedizierten Thread zum Ausführen der Nachrichtenwarteschlange. Nachrichtenwarteschlangen verwalten Anwendungsobjekte der obersten Ebene wie Aktivitäten, Broadcasts und Empfänger sowie die von ihnen erstellten Fenster.
Mit Handler können Sie einen weiteren Thread für die Kommunikation mit der Hauptanwendung erstellen. Verwenden Sie dazu im Voraus die Methoden post und sendMessage.
Runnables und Nachrichten werden in der Nachrichtenwarteschlange des Handlers geplant und zum entsprechenden Zeitpunkt ausgeführt.
class android.os.Handler
Handler ermöglicht die Kommunikation zwischen UI-Threads und Worker-Threads!
MessageQueue </ font> </ strong> (stapelt und speichert Nachrichten und Runnables) und ruft Nachrichten und Runnables aus MessageQueue in dem Thread ab, der die Handler-Instanz erstellt hat > Generieren Sie Looper </ font> </ strong>. Der Handler realisiert die Kommunikation zwischen Threads, sodass er anscheinend so konzipiert ist, dass er von anderen Threads referenziert werden kann </ font>.
Eine Instanz von Handler ist dem erzeugten Thread und der Nachrichtenwarteschlange zugeordnet und gibt true zurück, wenn eine Nachricht usw. zur Warteschlange hinzugefügt wird. Wenn Looper vor Ablauf der angegebenen Zeit beendet wird, wird Runnable abgebrochen und wird zu False. Wenn also False angezeigt wird, ist die Nachrichtenwarteschlange möglicherweise beendet!
Der Handler bietet eine Möglichkeit, Informationen zwischen bereits erstellten Threads zu kommunizieren. Es realisiert die Kommunikation zwischen Worker-Threads sowie UI-Threads.
Wenn Sie Message verwenden, verarbeitet Looper handleMessage, und wenn Sie Runnable verwenden, wird Runnable auf der UI-Seite ausgeführt.
Message
public class MainActivity extends AppCompatActivity {
TextView textView;
//UI-Thread(MainActivity)Erstellen Sie eine Handler-Instanz mit
//Jetzt sind sowohl MessageQueue als auch Looper UI-Threads.
//Da der Instanzhandler von einem anderen Thread aus referenziert werden kann
//Wenn Sie in einem anderen Thread auf den Handler verweisen und eine Nachricht posten
//UI-Thread (MainActivity)Und Looper erledigt das für Sie!
//Es ist cool! !!
//Dann kommen Sie bitte zum Handler!
Handler handler = new MyHandler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView1);
MyLovelyMessage();
}
private void MyLovelyMessage() {
//UI-Thread (MainActivity)Greifen Sie auf den in generierten Handler zu
//Legen Sie die Nachricht in den Handler und senden Sie die Nachricht!
//Der UI-Thread Looper sollte jetzt gut funktionieren!
Message message = handler.obtainMessage(1);
handler.sendMessage(message);
}
class MyHandler extends Handler{
@Override
public void handleMessage(Message message){
//Definiert, was das Handle im UI-Thread tut
//Es wird automatisch von Looper ausgeführt!
String msg = String.valueOf(message.what);
textView.setText(msg);
}
}
}
Vereinfachen Sie den obigen Code als interne Funktion
Message
public class MainActivity extends AppCompatActivity {
TextView textView;
Handler handler = new Handler(){
@Override
public void handleMessage(Message message){
String msg = String.valueOf(message.what);
textView.setText(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView1);
MyLovelyRunnable();
}
private void MyLovelyRunnable() {
Message message = handler.obtainMessage(1);
handler.sendMessage(message);
}
}
public class MainActivity extends AppCompatActivity {
TextView textView;
//Handler zum UI-Thread(MainAvtivity.class)Generieren mit
//Jetzt befinden sich sowohl MessageQueue als auch Looper in diesem Thread(UI-Thread)Verknüpft mit
//
//Da die Handler-Instanz auch von anderen Threads aus referenziert werden kann
//In einem anderen Thread mit dem Instanzhandler
//In diesem Thread ausführbar(UI-Thread)Wenn du es gibst
//Dieser Thread(UI-Thread-Seite)Kann Runnable ausführen
//Es ist schön!
//Jetzt erstellen wir eine Instanz von Handler! !!
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView1);
MyLovelyHandler();
}
private void MyLovelyHandler(){
new Thread(new Runnable() {
@Override
public void run() {
//UI-Thread(MainActivity)Die in erstellte Handler-Instanz
//Kann von anderen Threads referenziert werden
//Setzen Sie Runnable auf den Instanzhandler
//UI-Thread (MainActivity)Lassen Sie es uns übergeben und verarbeiten lassen!
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("I Love Handler");
}
});
}
}).start();
}
}
Mindestziel: api28 oder höher.
Erstellte Datei
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static TextView textView;
//Erstellen Sie ein Handler-Objekt und machen Sie MessageQueue und Looper zu einem UI-Thread!
//Dadurch wird die an das Handle-Objekt gesendete Nachricht in der MessageQueue gespeichert
//Looper wird es herausnehmen und verarbeiten! (Der Inhalt des Prozesses ist MyHandler.Definiere es in der Klasse! )
static MyHandler myHandler = new MyHandler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
//Erstellen Sie ein Intent-Objekt und rufen Sie den Service an!
Intent intent = new Intent(this,MyService.class);
startForegroundService(intent);
}
}
MyService.java
public class MyService extends Service {
public MyService() {
}
@Override
public int onStartCommand(Intent intent,int flags,int startid){
//SendMessage, indem Sie eine Nachricht in das Handle-Objekt von MainActivity einfügen!!
//Das Ziel ist MessageQueue des UI-Threads!
//Danach ist Looper MyHandler.Klasse ausführen und verarbeiten!!
Message message = MainActivity.myHandler.obtainMessage(1);
MainActivity.myHandler.sendMessage(message);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
MyHandler.java
//In MessageQueue des UI-Threads gespeicherte Nachricht
//Der UI-Thread Looper hat die folgende handleMessage()Wird durchgeführt!
public class MyHandler extends Handler {
@Override
public void handleMessage(Message message){
String msg = String.valueOf(message.what);
MainActivity.textView.setText(msg);
}
}
Ich durfte mich beziehen. Vielen Dank. Hier Aber ich habe nicht verstanden, warum `myHandler.postDelayed (runnnable, milli) zweimal aufgerufen wurde.
<Übersicht> Es verarbeitet keine Benachrichtigungen und stürzt daher sofort ab. Wechseln Sie automatisch zum Vordergrunddienst, wenn die App gestartet wird ForegroundService, Timer-Verarbeitung mit handler.postDeployed (ausführbar, Mühle) Setzen Sie die Zählung mit der Starttaste fort Stoppen Sie die Zählung mit der Stopptaste
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static TextView textView;
static Handler myHandler = new Handler();
boolean signal =false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnStart= findViewById(R.id.btnStart);
Button btnStop = findViewById(R.id.btnStop);
textView = findViewById(R.id.textView);
final Intent intent = new Intent(this,MyService.class);
startForegroundService(intent);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(signal == false){
MyService.runnable.run();
signal = true;
}
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myHandler.removeCallbacks(MyService.runnable);
signal = false;
}
});
}
}
MyService.java
public class MyService extends Service {
static Runnable runnable;
public MyService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startid) {
runnable = new Runnable() {
int i=0;
@Override
public void run() {
i++;
String st = String.valueOf(i);
MainActivity.textView.setText(st);
MainActivity.myHandler.postDelayed(this,1000);
}
};
// MainActivity.myHandler.postDelayed(runnable,1000);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}