Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Greenrobot's Eventbus : Two Fragments calling async tasks jobs got Eventbus confused

I am currently working on Fragments that was created under Activities with FragmentPagerAdapter. I used GreenRobot's EventBus 3.0 to return some AsyncTasks I created from a service class. However, since these two fragments are created one after the other, the return of the eventbus' post sticky got the subscribed fragments mixed up. I've scoured over stackoverflow, did what the others did (e.g. put the eventBus register to onStart and OnStop, etc..) and I still can't see even a similar issue. Hope you can help me. Thanks!

Here's are my two fragments : (I've omitted some of the unnecessary codes)

1. Status Fragment

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    Log.e(TAG, "StatusFragment onCreateView");
    eventBus = EventBus.getDefault();
    eventBus.register(this);
    StatusService statusService = StatusService.newInstance(getContext());
    statusService.getStatusList(); //Async Task to call onReturnAdapter once finished
    return mRecyclerView;
}

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onReturnList(List<Status> statuses) {
    Log.e(TAG, "onReturnList");
    mAdapter = new StatusRecyclerAdapter(statuses);
    mRecyclerView.setAdapter(mAdapter);
    eventBus.removeStickyEvent(statuses);
}

@Override
public void onStop() {
    Log.e(TAG, "onStop");
    eventBus.unregister(this);
    super.onStop();
}

2. Status Service - Service class for Status Fragment

public void getStatusList () {
    Log.e(LOG_TAG, "getStatusList");
    //do some async tasks here
    returnList(statuses);

}

private void returnList(List<Status> statuses) {
    Log.e(LOG_TAG, "returnList");
    eventBus.postSticky(statuses);
}

3. Chart Fragment

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    Log.e(LOG_TAG, "onCreateView");

    eventBus = EventBus.getDefault();
    eventBus.register(this);

    chartService = ChartService.newInstance(getContext());
    chartService.getDateResult(new DbRequestFeelings());
    return view;
}

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onReturnResults(List<Result> results) {
    Log.e(LOG_TAG, "onReturnResults");

    chartService.setupPieChart(results, feelingsPieChart);
}

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

4. Chart Service

public void getDateResult(final DbRequest dbRequest) {
    Log.e(LOG_TAG, "getDateResult");
    //do some async tasks
    returnResults(results);
}

private void returnResults(List<Result> results) {
    Log.e(LOG_TAG, "returnResults");
    eventBus.postSticky(results);
}

5. Result Class

public class Result {
      ....
}

6. Status Class

public class Status {
    ...
}

So every time the fragments were created, they call on their service class which in turn posts the List<Status> and List<Results> almost one after the other. Due to this, it created a confusion where it says that

03-11 11:48:19.685  15148-15148/com.paularagones.moode E/EventBus﹕ Could not dispatch event: class java.util.ArrayList to subscribing class class com.paularagones.moode.Fragments.ChartFragment
    java.lang.ClassCastException: com.paularagones.moode.Models.Status cannot be cast to com.paularagones.moode.Models.Result

Here's the full stack trace :

03-11 11:48:19.589  15148-15148/com.paularagones.moode E/Moode-StatusFragment﹕ StatusFragment onCreate
03-11 11:48:19.589  15148-15148/com.paularagones.moode E/Moode-StatusFragment﹕ StatusFragment onCreateView
03-11 11:48:19.605  15148-15148/com.paularagones.moode E/StatusService﹕ getStatusList
03-11 11:48:19.609  15148-15148/com.paularagones.moode E/ChartFragment﹕ onCreateView
03-11 11:48:19.613  15148-15148/com.paularagones.moode E/ChartService﹕ newInstance
03-11 11:48:19.621  15148-15148/com.paularagones.moode E/ChartService﹕ getDateResult
03-11 11:48:19.681  15148-15148/com.paularagones.moode E/RecyclerView﹕ No adapter attached; skipping layout
03-11 11:48:19.681  15148-15148/com.paularagones.moode E/StatusService﹕ returnList
03-11 11:48:19.681  15148-15148/com.paularagones.moode E/Moode-StatusFragment﹕ onReturnList
03-11 11:48:19.681  15148-15148/com.paularagones.moode E/ChartFragment﹕ onReturnResults
03-11 11:48:19.685  15148-15148/com.paularagones.moode E/EventBus﹕ Could not dispatch event: class java.util.ArrayList to subscribing class class com.paularagones.moode.Fragments.ChartFragment
    java.lang.ClassCastException: com.paularagones.moode.Models.Status cannot be cast to com.paularagones.moode.Models.Result
            at com.paularagones.moode.Services.ChartService.getData(ChartService.java:147)
            at com.paularagones.moode.Services.ChartService.setupPieChart(ChartService.java:129)
            at com.paularagones.moode.Fragments.ChartFragment.onReturnResults(ChartFragment.java:116)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at org.greenrobot.eventbus.EventBus.invokeSubscriber(EventBus.java:485)
            at org.greenrobot.eventbus.EventBus.postToSubscription(EventBus.java:420)
            at org.greenrobot.eventbus.EventBus.postSingleEventForEventType(EventBus.java:397)
            at org.greenrobot.eventbus.EventBus.postSingleEvent(EventBus.java:370)
            at org.greenrobot.eventbus.EventBus.post(EventBus.java:251)
            at org.greenrobot.eventbus.EventBus.postSticky(EventBus.java:292)
            at com.paularagones.moode.Services.StatusService.returnList(StatusService.java:80)
            at com.paularagones.moode.Services.StatusService.access$100(StatusService.java:24)
            at com.paularagones.moode.Services.StatusService$2.onNext(StatusService.java:72)
            at com.paularagones.moode.Services.StatusService$2.onNext(StatusService.java:59)
            at rx.Observable$30.onNext(Observable.java:8069)
            at rx.observers.SafeSubscriber.onNext(SafeSubscriber.java:139)
            at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:202)
            at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:162)
            at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4745)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)
03-11 11:48:19.685  15148-15148/com.paularagones.moode E/ChartService﹕ returnResults
03-11 11:48:19.685  15148-15148/com.paularagones.moode E/Moode-StatusFragment﹕ onReturnList
03-11 11:48:19.685  15148-15148/com.paularagones.moode E/ChartFragment﹕ onReturnResults
03-11 11:48:19.693  15148-15148/com.paularagones.moode E/StatusRecyclerAdapter﹕ onCreateViewHolder
03-11 11:48:19.697  15148-15148/com.paularagones.moode E/StatusRecyclerAdapter﹕ onBindViewHolder
03-11 11:48:19.709  15148-15148/com.paularagones.moode E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.ClassCastException: com.paularagones.moode.Models.Result cannot be cast to com.paularagones.moode.Models.Status
            at com.paularagones.moode.Adapters.StatusRecyclerAdapter.onBindViewHolder(StatusRecyclerAdapter.java:101)
            at com.paularagones.moode.Adapters.StatusRecyclerAdapter.onBindViewHolder(StatusRecyclerAdapter.java:28)
            at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5277)
            at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5310)
            at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4568)
            at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4461)
            at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1962)
            at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1371)
            at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1334)
            at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:563)
            at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2847)
            at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3145)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1627)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1034)
            at android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:744)
            at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
            at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1180)
            at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:757)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1649)
            at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1507)
            at android.widget.LinearLayout.onLayout(LinearLayout.java:1420)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1649)
            at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1507)
            at android.widget.LinearLayout.onLayout(LinearLayout.java:1420)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
            at android.view.View.layout(View.java:13754)
            at android.view.ViewGroup.layout(ViewGroup.java:4362)
            at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1866)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1687)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:998)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4212)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
            at android.view.Choreographer.doCallbacks(Choreographer.java:555)
            at android.view.Choreographer.doFrame(Choreographer.java:525)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4745)
            at java.lang.reflect.Method.invokeNative(Native Method)

Do you guys know any idea what is wrong with my code? Thanks.

like image 566
Paula Kristin Avatar asked Sep 24 '22 03:09

Paula Kristin


1 Answers

First thing that I noticed is that you aren't removing the sticky in your onReturnResults(List<Result> results) method ... not sure if that is on purpose or not ... but thought it should be mentioned.

The main point that I wanted to stress is with regards to having two onEvent() methods leveraging the same generic class List<> - this might very well be the issue - a small code change and quick test can verify this

Create a class for each List<>

public class Statuses
{
    List<Status> list;
    public Statuses(List<Status> data) { list = data; }
}

public class Results
{
    List<Result> list;
    public Results(List<Result> data) { list = data; }
}

Update your onEvent() method signatures:

public void onReturnList(Statuses statuses)
public void onReturnResults(Results results)

Update your .postSticky() method calls:

eventBus.postSticky(new Statuses(statuses));
eventBus.postSticky(new Results(results));

Of course, you'll need to access the Lists from their class member (for example):

foreach (var status in statuses.list)

and

foreach (var result in results.list)

If the problem you're seeing simply goes away after these changes are made - then it would make sense to assume that greenrobot's EventBus doesn't take into account the type contained within the generic List class during it's reflection calls seen in the callstack. It might simply look for the first matching signature that contains a List argument; and when there are 2 or more matches, the right one just might not get called.

This is guesswork; so you'll have to try it out and see if it helps -- but I've had success using greenrobot's EventBus in a project using this type of implementation when I need List<>s of classes to avoid ambiguity.

like image 93
Bret Avatar answered Sep 27 '22 03:09

Bret