5

I'm trying to implement the absolute basic implementation of EventBus Library for Android.

What I'm trying to simple input content by user in activity 1 and then instead of intent extras I'm using eventbus to post the entire object to the next activity - activity 2. I'm exactly following the given guidelines:

PART 1: POJO

public class StudentEvent {

  public final String registrationNumber ;
  public final String name ;
  public final String course ;
  public final String branch ;

  public StudentEvent(String registrationNumber, String name, String course, String branch) {
    this.registrationNumber = registrationNumber;
    this.name = name;
    this.course = course;
    this.branch = branch;
  }

  public String getRegistrationNumber() {
    return registrationNumber;
  }

  public String getName() {
    return name;
  }

  public String getCourse() {
    return course;
  }

  public String getBranch() {
    return branch;
  }
}

PART 2: Subscription in the second activity

EventBus.getDefault().register(this); //onCreate

EventBus.getDefault().unregister(this); //onDestroy

@Subscribe
public void eventReceiver(StudentEvent studentEvent){
  tvRegistrationNumber.setText(studentEvent.getRegistrationNumber());
  tvName.setText(studentEvent.getName());
  tvBranch.setText(studentEvent.getBranch());
  tvCourse.setText(studentEvent.getCourse());
}

PART 3: Post the event

StudentEvent studentEventObject = new StudentEvent(
            etRegistrationNumber.getText().toString(),
            etName.getText().toString(),
            etCourse.getText().toString(),
            etBranch.getText().toString()) ;

 EventBus.getDefault().post(studentEventObject);

I get the Error:

D/EventBus: No subscribers registered for event class co.swisdev.abhinav.eventbustesting.StudentEvent
D/EventBus: No subscribers registered for event class org.greenrobot.eventbus.SubscriberExceptionEvent

WHAT AM I MISSING?
It is working when I make the subscription in the same class.

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
Abhinav Das
  • 306
  • 1
  • 4
  • 12

6 Answers6

15

Though this is not an answer, but I think this is relevant to EventBus user. Per EventBus documentation, we need to register to EventBus in onStart() and unregister in onStop()

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

@Override
public void onStop() {
   EventBus.getDefault().unregister(this);
    super.onStop();
}
ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
11

This seems to be a timing issue. Activity 2 must be registered to receive the event. If you are posting the event from Activity 1, there is no guarantee that Activity 2 has been created.

Jesse Buss
  • 833
  • 6
  • 13
  • Correct answer, but needs to be fleshed out a bit more to be a great answer. You might want point to Activity Lifecycle and explain why this isn't even remotely the correct application of an EventBus. – 323go Apr 17 '16 at 05:45
  • 1
    What's the best modification that I must do then? Should I make the intent and then post event to EventBus? @323go – Abhinav Das Apr 17 '16 at 05:53
  • @AbhinavJordiieDas This isn't the type of thing that the EventBus is typically used for. In general, the EventBus is used to receive updated data for an already active activity or fragment. Think of the EventBus as more of a wrapper around an observer/consumer. For this example it looks like you are using it to pass data to another Activity. I think you're better off using standard means to do so, using a bundle, or saving it to a model and accessing the model in Activity 2. – Jesse Buss Apr 17 '16 at 14:46
  • @JesseBuss Can Event bus be a viable replacement for [Parceler](https://github.com/johncarl81/parceler) ? – Abhinav Das Apr 17 '16 at 14:58
  • @AbhinavJordiieDas They seem to do different things for me. A Parceler makes it easier to pass data to a new Activity. I think in this example, a Parceler will be a good option! Now let's say you have a network request to grab the most recent StudentEvent. We launch Activity 2, then after a few minutes we get the new StudentEvent. Now would be the time to post a new StudentEventReceived event, to alert the Activity that new data is available. – Jesse Buss Apr 17 '16 at 15:02
  • Way off, mate. Seems like you might be storing data in your UI, rather than keeping those bits separate. Create a class to hold your data objects, modify those, and then populate your activities as you resume them. Don't forget to store data on pause. Or you can use Android's (new) databinding, or robobinding, or similar. – 323go Apr 18 '16 at 05:31
  • Thanks a lot @JesseBuss! and @323go, I was just testing the library, so, that was the most simplest code I could have written. Anyways, thanks to you too, :) – Abhinav Das Apr 20 '16 at 02:27
  • I confirm: I just added a brutal "Thread.sleep(2000)" before posting the event and everything was gone right. Note: I had the same problem upon picking up a contact from the native contacts list, so the problem could be related to the needs of re-load the activity. – Marco Ottina May 20 '20 at 12:37
  • IMPORTANT EDIT: As @Saiful Islam Sajib suggested, change from "post(..." to "postSticky(..." and remember to add "sticky = true" to your "@Subscribe" tag. This resolves completely and elegantly the problem. – Marco Ottina May 20 '20 at 12:56
5

You should try to use @Subscribe(sticky = true) annotation in "Activity 2", and call bus.postSticky(...) method in "Activity 1".

Documentation

ytrikoz
  • 51
  • 2
  • 2
2

You have to use sticky event because you are posting the StudentEvent but no subscriber found yet as subscriber Activity doesn't created yet. If you use postSticky then event bus will hold this event on memory and deliver it when a subscriber found in future.

See the following example:

Part 1:

public class StudentEvent {

public final String registrationNumber ;
public final String name ;
public final String course ;
public final String branch ;

public StudentEvent(String registrationNumber, String name, String course, 
String branch) {
this.registrationNumber = registrationNumber;
this.name = name;
this.course = course;
this.branch = branch;
}

public String getRegistrationNumber() {
 return registrationNumber;
}

public String getName() {
 return name;
}

public String getCourse() {
 return course;
}

public String getBranch() {
 return branch;
}
}

Part 2: Subscribe as Sticky

EventBus.getDefault().register(this); //onCreate

EventBus.getDefault().unregister(this); //onDestroy

@Subscribe(sticky = true)
public void eventReceiver(StudentEvent studentEvent){
tvRegistrationNumber.setText(studentEvent.getRegistrationNumber());
tvName.setText(studentEvent.getName());
tvBranch.setText(studentEvent.getBranch());
tvCourse.setText(studentEvent.getCourse());
}

Part 3: Post Sticky event

 StudentEvent studentEventObject = new StudentEvent(
        etRegistrationNumber.getText().toString(),
        etName.getText().toString(),
        etCourse.getText().toString(),
        etBranch.getText().toString()) ;

 EventBus.getDefault().postSticky(studentEventObject);

Good luck...!

Saiful Islam Sajib
  • 2,243
  • 1
  • 12
  • 17
1

Had this same issue, maybe this might help. This is a timing issue as stated by @JesseBuss because Activity2 must be fully created and registered to receive events. However there is a way to ensure transfer of the object from Activity1 to Activity2, but requires a bit more code. To do this, Activity2 should subscribe to an event that will be posted by Activity1 and Activity1 should also subscribe to an event that will be posted by Activity2. For instance :

Activity1

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    EventBus.getDefault().register(this); //register here or onStart, etc
}

private void startActivity2(){//Start activity2 without any extras
    //Intent Activity2
    //startActivity(Activity2)
}


@Subscribe
public void eventFromActivity2(String fromActivity2){
//subscribe to an event to be posted by activity2 (e.g a String).
//At this point Activity2 should be fully created to respond to events from Activity1

     StudentEvent studentEventObject = new StudentEvent(
            etRegistrationNumber.getText().toString(),
            etName.getText().toString(),
            etCourse.getText().toString(),
            etBranch.getText().toString()) ;

      EventBus.getDefault().post(studentEventObject);//post event back to Activity2

      EventBus.getDefault().unregister(this);//unregister

}

Activity2

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    EventBus.getDefault().register(this);//register here

    // after completing onCreate, post event to Activity1
    EventBus.getDefault().post("to Activity1");
}

protected void onDestroy() {

    EventBus.getDefault().unregister(this); //unregister here
    super.onDestroy();
}

@Subscribe
public void eventReceiver(StudentEvent studentEvent){ //respond to event from Activity1
    tvRegistrationNumber.setText(studentEvent.getRegistrationNumber());
    tvName.setText(studentEvent.getName());
    tvBranch.setText(studentEvent.getBranch());
    tvCourse.setText(studentEvent.getCourse());
}

Also be sure to unregister from events properly

Tokoni K
  • 11
  • 1
0

If don't put EventBus.getDefault().register(this); into onCreate. onEvent Lisneteners can not catch the fire.

activity.java

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_fragment_layout);

        EventBus.getDefault().register(this);

    }

    public void onEvent(AccountSelectedEvent event) {
        FragTaxCustomsInfo frag = (FragTaxCustomsInfo) getSupportFragmentManager()
                .findFragmentByTag(FragTaxCustomsInfo.TAG);
        frag.paymentSelected();
    }

    public void onEvent(AccountSelectedUpdateIndexEvent event) {
        FragTaxCustomsInfo frag = (FragTaxCustomsInfo) getSupportFragmentManager()
                .findFragmentByTag(FragTaxCustomsInfo.TAG);
        frag.setSelectedPayment(event.getIndex(), false);
    }
Samet ÖZTOPRAK
  • 3,112
  • 3
  • 32
  • 33