im Thread auf Eventbus zugreifen bzw über Eventbus auf Thread zugreifen

  • Antworten:20
Steve bennet
  • Forum-Beiträge: 14

11.05.2015, 11:00:28 via Website

Hallo,

ich kämpfe grade mit Threads und Handler und komme nicht weiter. Jetzt habe ich den Eventbus gefunden der mir vielleicht weiterhelfen kann. Also im MainThread läuft der Eventbus testweise nur Thread-übergreifend noch nicht. Hat jemand schon damit Erfahrung?

— geändert am 11.05.2015, 17:45:32

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

11.05.2015, 12:40:37 via Website

Ja ein wenig, was genau läuft denn schief?
Im schlimmsten Fall musst Du den Bus mit einem Wrapper versehen, der prüft auf welchem Thread er grade läuft und wenn es NICHT der UI Thread ist, das Event auf den UI Thread umleitet.

Auch wichtig: Wenn Du den EventBus nutzt, musst Du die proguard config anpassen, um die onEvent Methoden zu erhalten.

— geändert am 11.05.2015, 12:41:24

Antworten
Klaus
  • Blogger
  • Forum-Beiträge: 19.172

11.05.2015, 12:47:27 via Website

Hallo Steve!

Herzlich Willkommen hier bei uns im Forum. :)

Bitte beachte, dass Threads mit nicht aussagekräftigem Titel bei uns üblicherweise den Regeln entsprechend entfernt werden. Ich bitte dich daher, deinen Threadtitel innerhalb der nächsten 24 Stunden, spätestens jedoch bei deinem nächsten Besuch etwas aussagekräftiger zu gestalten (Hierfür einfach unter deinem ersten Beitrag auf "Bearbeiten" klicken, dann kannst du oben noch mal den Titel anpassen)

Danke :)

| LG Klaus |
| Google Nexus 6P - Dirty Unicorns | Google Nexus 6 - Dirty Unicorns |
| Das AndroidPITiden-Buch | Die Androiden-Toolbox | AndroidPIT-Regeln |

Antworten
Steve bennet
  • Forum-Beiträge: 14

11.05.2015, 18:02:10 via Website

Hey danke für die Antwort!

Was Threads und Eventbus angeht stehe ich noch am Anfang. Eigentlich habe ich das Problem vom Main-Thread auf einem TCP-Thread über einen Händler eine Funktion auszulösen. Die empfangenen Daten vom TCP-Thread zum Main-Thread über einen Handler zu schicken geht, nur anderdherum eben noch nicht :(
Jetzt dachte ich der Eventbus kann "entkoppelt" Daten verschicken, also die Handler und Loopersache könnte ich mir ersparen, aber anscheinend nicht. aber wie erwähnt stehe ich erst am Anfang vielleicht gehts ja doch einfacher.
Momentan habe ich den Eventbus im Main-Thread laufen, und per buttonclick löse ich einen event aus. Jetzt würde ich gerne diesen Event in meinem TCP-Thread auslösen. Ich habe aber noch keine Tutorial gefunden wo sowas beschrieben ist. Wie sieht evtl. so ein Wrapper aus?
Wie ich die proguard config anpassen muß schaue ich mir jetzt an.

— geändert am 11.05.2015, 18:11:20

Antworten
Ju Ku
  • Forum-Beiträge: 72

13.05.2015, 19:43:53 via Website

ist es ein Activity Thread oder ist es ein Service Thread?
Wenn du einen Service Thread nutzt oder den Thread als Service auslagerst, kannst du AIDL verwenden.

Antworten
Steve bennet
  • Forum-Beiträge: 14

18.05.2015, 10:18:12 via Website

Vielen Dank für die Anregungen.
Ich wollte gerne einen Thread (class Thread keinen service) benutzen, ich probier nochmal und wenn 's gar nicht will post ich demnächst den code hier.

— geändert am 18.05.2015, 15:24:09

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

18.05.2015, 21:54:52 via App

Also vom TCP Thread in den Main inst klar da brauchst du einen Handler oder callback etc. Aber anderherum kannst du das auch mit synchronized lösen
So habe ich es jedenfalls mit einem BuetoothThread gemacht und hat funktioniert. Nur die beste Methode ist das wahrscheinlich nicht..

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

19.05.2015, 09:36:44 via App

Ich weiss jetzt nich ob das was damit zutun hat.

synchronized(mThreadInstance)
{
mThreadInstance.send(data);

}

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

19.05.2015, 09:44:00 via Website

Damit serialisierst Du nur die Zugriffe aus X Threads auf 1 Objekt, um überschneidende (und damit potenziell nicht deterministische) Änderungen des Zustandes zu verhindern.

Denke hier geht es eher darum, dass Events, die vom UI-Thread in Richtung TCP-Thread gefeuert werden, zu einem "NetworkOnMainThread" Fehler führen und Events, die vom TCP-Thread Richtung UI gefeuert werden zu einem Fehler beim Zugriff auf die UI führen.

Ohne Code können wir da aber genau so gut in die Glasguckel gucken und Nebel deuten :)

— geändert am 19.05.2015, 09:44:53

Antworten
Steve bennet
  • Forum-Beiträge: 14

21.05.2015, 11:45:05 via Website

Rafael hat mein Problem fast genau geblickt, der Zugriff per handler auf den UI-Thread funktioniert allerdings. Ich wollte mal den Eventbus testen komme aber nicht klar. Ich weiß nicht wie ich die Events händeln soll. mein Thread schickt alle paar ms ne post die kommt aber nur im selben thread an, ebenso wenn ich den button klicke passierts nur im UIThread. Die Nachrichten eines Threads sollen halt im anderen thread ankommen. hier mal mein Testcode (also nicht schlagen Anfänger in sachen threads, eventbus etc)

package com.example.handlerexample;

//import com.example.handlerexample.BackgroundThread2.MyEvent;

import de.greenrobot.event.EventBus;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.util.Log;

public class MainActivity extends Activity {

 String tag =  "MainActivity" ;  
public Button btnclick;

public BackgroundThread2 MyBack;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    btnclick = (Button) findViewById(R.id.button1);
    MyBack = new BackgroundThread2();
    MyBack.start();
    EventBus.getDefault().register(this);
}


@Override
public void onStart() {
    super.onStart();
    //EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

public void onEventMainThread(MessageEvent event) {
    Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show();
}

public void btnclick(View view){ //o
     Log.d("Ui- ","button clicked ");       
     EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
}

public class MessageEvent {
    public final String message;
    public MessageEvent(String message) {
        this.message = message;
    }
}

public  class  MyEvent {  
    private  boolean  IsBoolean;  
    public  MyEvent ( boolean  IsBoolean) {  
        this .IsBoolean = IsBoolean;  
    }  
    public  boolean  isMyEvent () {  
        return  this .IsBoolean;  
    }  
}  

}

Der Thread:

package com.example.handlerexample;

import de.greenrobot.event.EventBus;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.EventLog.Event;
import android.util.Log;

public class BackgroundThread2 extends Thread{
//@Inject EventBus bus;

private int counter;
private String tag = "Thread ey";
//constructor

public void onEvent(MyEvent Event){
    Log.d (tag, "OnEvent: " + "thread:" + Thread.currentThread().getId ());  
}


public void onEvent(MessageEvent event){
    Log.d (tag, "OnEvent: " + event.message + "thread:" + Thread.currentThread().getId ());  
}

@Override
public void run() {
    EventBus.getDefault().register(this);
    while(true){
        try {
            //parentHandler.sendEmptyMessage(4);
            counter++;
            if (counter >= 5){
                counter =0;
                 EventBus.getDefault().postSticky(new MessageEvent("message from thread"));
            }

              Thread.sleep(500 );
              System.out.println( "warte. counter" + counter +" Threadid: " + Thread.currentThread().getId () );

            } catch ( InterruptedException e ) { e.printStackTrace(); }
          }
}

 public class MessageEvent {
        public final String message;
        public MessageEvent(String message) {
            this.message = message;
        }
    }

public  class  MyEvent {  
            // **  Judgments based * /  
       private  boolean  IsBoolean;  
            public  MyEvent ( boolean  IsBoolean) {  
                this .IsBoolean = IsBoolean;  
            }  
            public  boolean  isMyEvent () {  
                return  this .IsBoolean;  
            }  
   }        

}// das ende

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.05.2015, 12:27:52 via Website

Da sehe ich schon 2 Fehler.
Zum einen solltest du die Activity im Bus in onStart registrieren, sonst ist die Registrierung nach einmal Minimieren/Maximieren weg.
Schau dir mal die Doku zum Lifecycle einer Activity an.

Zum anderen hast Du die Klasse MessageEvent in beiden Klassen einzeln deklariert und sendest in beiden Klassen ein Event mit der INNEREN Klasse als Parameter. Natürlich erkennt der EventBus dann, dass der Parameter NICHT INSTANCEOF Activity.MessageEvent sondern Thread.MessageEvent ist und ruft die Methode NICHT auf.

Also lager diese Event Klassen in einzelne Dateien aus und verwende in beiden Klassen DIESELBE MessageEvent zum Senden/Empfangen des Events.

— geändert am 21.05.2015, 12:28:51

Steve bennet

Antworten
Steve bennet
  • Forum-Beiträge: 14

22.05.2015, 10:11:51 via Website

Ja danke, jetzt klappts mit dem Bus :D

Ich hab die Eventklassen ausgelagert und es funktionierte sofort. Die Registrierung hatte ich ja zuerst im Oncreate und wenn ich sie zusätzlich im onStart mache gib es nen Fehler. Jetzt ist die Registrierung nur im onStart, das müsste genügen.

Jetzt teste ich noch den Eventbus in meiner Steuerungssoftware zusammen mir den Netzwerkfunktionen.
Aber bis hierhin vielen Dank für die Hilfe!

Antworten
Steve bennet
  • Forum-Beiträge: 14

24.05.2015, 15:30:29 via Website

Hi an alle,
hab wieder mal eine Fehlermeldung bzw ein Verständnisproblem. Über den Eventbus schicke ich einen Buttonclickevent zum Thread, dort möchte ich ein Tcp Socket erstellen. Wenn ich die Connect-Funktion direct im OnEvent aufrufe bekommet ich fehlermeldungen siehe logcat:

im Background Thread:
public void onEvent(MessageEvent_toT event){
Log.d (tag, "OnEvent: " + "thread:" + event.message);
//goconnect= true;
connect();
}

05-24 13:24:33.706: D/gralloc_goldfish(999): Emulator without GPU emulation detected.
05-24 13:24:35.026: D/Thread ey(999): OnEvent: thread:Text from UI Thread
05-24 13:24:35.026: I/System.out(999): im thread: try to connect ...
05-24 13:24:35.086: E/Event(999): Could not dispatch event: class com.example.handlerexample.MessageEvent_toT to subscribing class class com.example.handlerexample.BackgroundThread2
05-24 13:24:35.086: E/Event(999): android.os.NetworkOnMainThreadException
05-24 13:24:35.086: E/Event(999): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1084)
05-24 13:24:35.086: E/Event(999): at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:74)
05-24 13:24:35.086: E/Event(999): at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
05-24 13:24:35.086: E/Event(999): at libcore.io.IoBridge.connect(IoBridge.java:112)
05-24 13:24:35.086: E/Event(999): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
05-24 13:24:35.086: E/Event(999): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
05-24 13:24:35.086: E/Event(999): at java.net.Socket.startupSocket(Socket.java:566)
05-24 13:24:35.086: E/Event(999): at java.net.Socket.tryAllAddresses(Socket.java:127)
05-24 13:24:35.086: E/Event(999): at java.net.Socket.(Socket.java:177)
05-24 13:24:35.086: E/Event(999): at java.net.Socket.(Socket.java:149)
05-24 13:24:35.086: E/Event(999): at com.example.handlerexample.BackgroundThread2.connect(BackgroundThread2.java:33)
05-24 13:24:35.086: E/Event(999): at com.example.handlerexample.BackgroundThread2.onEvent(BackgroundThread2.java:26)
05-24 13:24:35.086: E/Event(999): at java.lang.reflect.Method.invokeNative(Native Method)
05-24 13:24:35.086: E/Event(999): at java.lang.reflect.Method.invoke(Method.java:511)
05-24 13:24:35.086: E/Event(999): at de.greenrobot.event.EventBus.invokeSubscriber(EventBus.java:498)
05-24 13:24:35.086: E/Event(999): at de.greenrobot.event.EventBus.postToSubscription(EventBus.java:429)
05-24 13:24:35.086: E/Event(999): at de.greenrobot.event.EventBus.postSingleEventForEventType(EventBus.java:410)
05-24 13:24:35.086: E/Event(999): at de.greenrobot.event.EventBus.postSingleEvent(EventBus.java:383)
05-24 13:24:35.086: E/Event(999): at de.greenrobot.event.EventBus.post(EventBus.java:263)
05-24 13:24:35.086: E/Event(999): at com.example.handlerexample.MainActivity.btnclick(MainActivity.java:82)
05-24 13:24:35.086: E/Event(999): at java.lang.reflect.Method.invokeNative(Native Method)
05-24 13:24:35.086: E/Event(999): at java.lang.reflect.Method.invoke(Method.java:511)
05-24 13:24:35.086: E/Event(999): at android.view.View$1.onClick(View.java:3034)
05-24 13:24:35.086: E/Event(999): at android.view.View.performClick(View.java:3480)
05-24 13:24:35.086: E/Event(999): at android.view.View$PerformClick.run(View.java:13983)
05-24 13:24:35.086: E/Event(999): at android.os.Handler.handleCallback(Handler.java:605)
05-24 13:24:35.086: E/Event(999): at android.os.Handler.dispatchMessage(Handler.java:92)
05-24 13:24:35.086: E/Event(999): at android.os.Looper.loop(Looper.java:137)
05-24 13:24:35.086: E/Event(999): at android.app.ActivityThread.main(ActivityThread.java:4340)
05-24 13:24:35.086: E/Event(999): at java.lang.reflect.Method.invokeNative(Native Method)
05-24 13:24:35.086: E/Event(999): at java.lang.reflect.Method.invoke(Method.java:511)
05-24 13:24:35.086: E/Event(999): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
05-24 13:24:35.086: E/Event(999): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
05-24 13:24:35.086: E/Event(999): at dalvik.system.NativeStart.main(Native Method)
05-24 13:24:35.086: D/Event(999): No subscribers registered for event class de.greenrobot.event.SubscriberExceptionEvent

Wen ich die Connect-Funktion in der Run-Funktion des Threads benutze gehts. Was ist der Unterschied zwischen OnEvent- und der run-Funktion?

— geändert am 24.05.2015, 16:17:33

Antworten
Steve bennet
  • Forum-Beiträge: 14

26.05.2015, 22:37:33 via Website

Dieser Fehler ( NetworkOnMainThreadException ) verfolgt mich! Korrigier mich wenn ich falsch liege, er tritt auf wenn ich aus dem UI-Thread heraus zeitintensive Sachen wie z.B.Inet-Downloads oder TCP- Netzwerkzugriffe machen will. Das ist ja mein Hauptproblem.

Ich möchte per Android-Tablett mit einer Logo!-Sps kommunizieren(private Haussteuerung). Ich hab mir eine kleine App geschrieben mit der ich die Relais schalten und die Eingänge auslesen kann, die läuft unter 2.3 auf meinem Handy. Das Tablett hat Android 4.0 und seit 3.0 gehen wohl Netzwerkzugriffe nicht mehr im UI-Thread. Jetzt bekomme ich diese exception. Mir ist es auch mit den Handlern nicht gelungen die Threads so trennen oder verbinden ?!?, dass es in beide Richtungen ordentlich geht.
Wie ich einen Wrapper für den Eventbus erstelle oder die Handler/Looper richtig einsetzte weiß ich eben nicht.
Meine Logo! müßte, wenn die App läuft, andauernd mit Daten austauschen (z.B Eingänge lesen Temperatur lesen etc). Des wegen glaube ich, dass es mit HanderThreads uns Async nicht geht, sondern evtl. mit nem Service oder nem Thread. Aber beides gelingt mir nicht, ich hoffte der Eventbus wäre einfacher.
Aber vielleicht hast Du ein Tutorial wo es verständlich beschrieben ist z.B. einen Wrapper für einen Eventbus zu machen? Oder andere Info?

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

26.05.2015, 23:22:09 via Website

Mit einem Handler leitest Du die Ausführung ja grade auf den UI Thread. z.B. um sicherzustellen, dass Zugriffe auf die UI nur dort erfolgen.
Für nebenläufige Netzwerkzugriffe nutzt man in der Regel AsyncTask, oder Service bzw. IntentService.
Beide Fälle kannst Du also mit diesen Mitteln abfischen.

Das geht definitiv, evtl. musst halt ein paar Grundlagen aufarbeiten.

Zum Thema Wrapper:
Du musst es noch nichtmal so kompliziert machen. Sorge einfach in den jeweiligen onEvent Methoden dafür, dass die Ausführung auf den richtigen Thread geleitet wird.
Alles was die UI verändert -> Handler
Alles was lange dauert und/oder auf Netzwerk zugreift -> AsyncTask/IntentService

— geändert am 26.05.2015, 23:59:52

Antworten
Steve bennet
  • Forum-Beiträge: 14

27.05.2015, 21:01:08 via Website

Wenn ich das richtig verstanden habe sind Asynctask und Handlerthreads dafür da eine Aktion einmalig im Hintergrund abzuarbeiten ohne dabei den Mainthread zu blockieren. Ich brauche aber einen Thread oder Service der andauernd mit der Sps reden kann und auch auf meine Eingaben reagieren kann. Wie ich schon oben ausführte klappt es mit nem Thread nicht richtig. Vom Thread zum Mainthread gehts, da ich da den Handler beim Erzeugen des Threads mitgeben kann. Ich krieg die Messages (meine Buttonklicks )vom Mainthread nicht zum TCP-Thread geschickt (NetworkOnMainThreadException,obwohl ich mir nen Handler vom TCP-Thread hole). Ich mache da wahrscheinlich irgendeinen blöden Fehler, bin da irgenwie blockiert. Vielleicht mach ich nen 2. Anlauf mit nem Service obwohl die Beispiele mit TCP-Socket auch Threads im Service benuzten. Naja wahrscheinlich lasse ich die Sache erstmal für paar Wochen liegen.
Aber danke für Infos und Tipps

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

28.05.2015, 09:13:12 via Website

Steve bennet

Wenn ich das richtig verstanden habe sind Asynctask und Handlerthreads dafür da eine Aktion einmalig im Hintergrund abzuarbeiten ohne dabei den Mainthread zu blockieren.

Das sind zwei unterschiedliche Dinge. AsyncTask läuft NIE auf dem UI-Thread. Handler führt die Runnables auf dem Thread aus, mit dem man ihn konfiguriert (in dem man ihn erzeugt) und das ist in den allermeisten Fällen der UI-Thread. Darum ist ja klar, dass auch Netzwerk Zugriffe im Handler knallen.

Steve bennet

Ich brauche aber einen Thread oder Service der andauernd mit der Sps reden kann und auch auf meine Eingaben reagieren kann.

Dafür brauchst Du eher ZWEI Threads. Den UI-Thread kriegst Du von der Plattform geschenkt und der reagiert auf Deine Eingaben.
Wie Du die Kommunikation mit dem SPS regelst, ist dir überlassen. Du kannst aus dem UI-Thread in periodischen Abständen einen AsyncTask starten, der einen Netzwerk Request macht und dann die Oberfläche aktualisiert (Polling), um die Daten der SPS anzuzeigen.
Wenn Du Kommandos an die SPS sendest, führt halt ein Button-Click in der Oberfläche ebenfalls zur Ausführung eines AsyncTask, der den Netzwerk Request macht.

Du kannst es auch mit einem Service aufziehen, der auch mit SPS redet, wenn die App nicht im Vordergrund läuft...viele Wege führen nach Rom.

Antworten
Steve bennet
  • Forum-Beiträge: 14

31.05.2015, 21:58:53 via Website

Ja danke für diese Anregung. Ich probier das grade aus. Mal sehen ob das zeitmäßig hinhaut, bei jedem Button klick mach ich einen neuen AsynTask auf der sich verbinden muß (Socket erstellt, sps Kanal erstellt etc und wieder abbaut). momentan kann ich das nicht direkt testen ob das alles schnell genug geht, da ich die sps nicht da habe. Kann aber sein das ich mich bald wieder melde.

Antworten