Eventbus event never gets to the fragment
Asked Answered
P

2

7

I have a Fragment A which on a click of a button will start Fragment B that contains a RecyclerView. In Fragment B, on click of an item EventBus is started and that value needs to be passed to Fragment A. But, for some reason, the value never reaches Fragment A.

Fragment A

    public class OrderSummaryFragment extends BaseFragment implements OrderSummaryView {
    private static final String ARG_PARAM1 = "param1";
    public static final String ACTION_BACK = OrderSummaryFragment.class.getName() + ".back";
    public static final String ACTION_HIDE_ACTION_BAR = OrderSummaryFragment.class.getName() + ".hide_action_bar";
    public static final String ACTION_SHOW_ACTION_BAR = OrderSummaryFragment.class.getName() + ".show_action_bar";
    public static final String ACTION_CHANGE_ADDRESS = OrderSummaryFragment.class.getName() + ".select_address";

    FragmentOrderSummaryBinding mBinder;
    Shop mShop;
    OrderSummaryPresenter mPresenter;

    public OrderSummaryFragment() {

    }

    public static OrderSummaryFragment newInstance(Shop shop) {
        OrderSummaryFragment fragment = new OrderSummaryFragment();
        Bundle args = new Bundle();
        args.putParcelable(ARG_PARAM1, Parcels.wrap(shop));
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            Parcelable parcelable;
            parcelable = getArguments().getParcelable(ARG_PARAM1);
            mShop = Parcels.unwrap(parcelable);
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mBinder = DataBindingUtil.inflate(inflater, R.layout.fragment_order_summary, container, false);
        mPresenter = new OrderSummaryPresenterImpl(this);
        sendActionToActivity(ACTION_HIDE_ACTION_BAR);
        setUIListeners();
        EventBus.getDefault().register(this);
        return mBinder.getRoot();
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mPresenter.loadBillingAddress(mShop);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        sendActionToActivity(ACTION_SHOW_ACTION_BAR);
        EventBus.getDefault().unregister(this);
        mPresenter.cleanup();
    }

    @Override
    protected void setTypeface() {
        mBinder.tvBackButton.setTypeface(FontManager.getInstance().getFontAwesome());
    }

    private void setUIListeners() {
        mBinder.tvBackButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendActionToActivity(ACTION_BACK);
            }
        });
        mBinder.btnChange.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendActionToActivity(ACTION_CHANGE_ADDRESS, mShop);
            }
        });
    }

    @Override
    public void renderBillingAddress(UserInfo userInfo) {
        mBinder.setUserInfo(userInfo);
        if (userInfo.getAddress2().equals("")) {
            mBinder.tvBillingAddress2.setVisibility(View.GONE);
        }
    }

    @Override
    public void renderPaymentTerms(List<PaymentInfo> paymentInfoList) {

    }

    @Override
    public void renderDeliveryMethod(List<DeliveryInfo> deliveryInfoList) {

    }

    @Override
    public void showProgress(boolean show) {

    }

    @Override
    public void showError(Error error) {

    }

    private void sendActionToActivity(String action) {
        if (mListener == null) {
            return;
        }
        Bundle bundle = new Bundle();
        bundle.putString(Constants.ACTION_KEY, action);
        mListener.onFragmentInteraction(bundle);
    }

    private void sendActionToActivity(String action, Shop shop) {
        if (mListener == null) {
            return;
        }
        Bundle bundle = new Bundle();
        bundle.putString(Constants.ACTION_KEY, action);
        bundle.putParcelable(Constants.DATA_KEY_1, Parcels.wrap(shop));
        mListener.onFragmentInteraction(bundle);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessage(ShippingAddressResult event) {
        UserInfo userInfo = event.getUserInfo();
        Log.d("Tag", "Test" + userInfo);
    }
}

Fragment B

    public class ShippingAddressFragment extends BaseFragment implements ShippingAddressView,
        ShippingAddressAdapter.OnItemInteractionListener {
    private static final String ARG_PARAM1 = "param1";
    public static final String ACTION_BACK = ShippingAddressFragment.class.getName() + ".back";
    public static final String ACTION_HIDE_ACTION_BAR = ShippingAddressFragment.class.getName() + ".hide_action_bar";
    public static final String ACTION_SHOW_ACTION_BAR = ShippingAddressFragment.class.getName() + ".show_action_bar";
    public static final String ACTION_NEW_ADDRESS = ShippingAddressFragment.class.getName() + ".new_address";

    FragmentShippingAddressBinding mBinder;
    Shop mShop;
    ShippingAddressAdapter mAdapter;
    ShippingAddressPresenterImpl mPresenter;
    List<UserInfo> mUserInfoList;

    public ShippingAddressFragment() {

    }

    public static ShippingAddressFragment newInstance(Shop shop) {
        ShippingAddressFragment fragment = new ShippingAddressFragment();
        Bundle args = new Bundle();
        args.putParcelable(ARG_PARAM1, Parcels.wrap(shop));
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            Parcelable parcelable;
            parcelable = getArguments().getParcelable(ARG_PARAM1);
            mShop = Parcels.unwrap(parcelable);
        }
        mUserInfoList = new ArrayList<>();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mBinder = DataBindingUtil.inflate(inflater, R.layout.fragment_shipping_address, container, false);
        setUIListener();
        mPresenter = new ShippingAddressPresenterImpl(this);
        sendActionToActivity(ACTION_HIDE_ACTION_BAR);
        mAdapter = new ShippingAddressAdapter(getContext(), mUserInfoList);
        mAdapter.addOnInteractionListener(this);
        LinearLayoutManager manager = new LinearLayoutManager(getContext());
        mBinder.rvShippingAddress.setLayoutManager(manager);
        mBinder.rvShippingAddress.addItemDecoration(new DividerItemDecoration(getActivity()));
        mBinder.rvShippingAddress.setAdapter(mAdapter);
        return mBinder.getRoot();
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mPresenter.loadShippingAddress(mShop);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mPresenter.cleanup();
        sendActionToActivity(ACTION_SHOW_ACTION_BAR);
        mAdapter.removeInteractionListener();
    }

    @Override
    protected void setTypeface() {
        mBinder.tvBackButton.setTypeface(FontManager.getInstance().getFontAwesome());
    }

    private void setUIListener() {
        mBinder.tvBackButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendActionToActivity(ACTION_BACK);
            }
        });
        mBinder.fabNewAddress.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendActionToActivity(ACTION_NEW_ADDRESS, mShop);
            }
        });
    }

    @Override
    public void onClick(UserInfo userInfo) {
        selectedShippingAddress(userInfo);
        sendActionToActivity(ACTION_BACK);
    }

    @Override
    public void renderShippingAddress(List<UserInfo> userInfoList) {
        mUserInfoList.clear();
        mUserInfoList.addAll(userInfoList);
        mAdapter.notifyDataSetChanged();
    }

    private void sendActionToActivity(String action) {
        if (mListener == null) {
            return;
        }
        Bundle bundle = new Bundle();
        bundle.putString(Constants.ACTION_KEY, action);
        mListener.onFragmentInteraction(bundle);
    }

    private void sendActionToActivity(String action, Shop shop) {
        if (mListener == null) {
            return;
        }
        Bundle bundle = new Bundle();
        bundle.putString(Constants.ACTION_KEY, action);
        bundle.putParcelable(Constants.DATA_KEY_1, Parcels.wrap(shop));
        mListener.onFragmentInteraction(bundle);
    }

    private void sendActionToActivity(String action, Shop shop, AllCheckoutInfo allCheckoutInfo) {
        if (mListener == null) {
            return;
        }
        Bundle bundle = new Bundle();
        bundle.putString(Constants.ACTION_KEY, action);
        bundle.putParcelable(Constants.DATA_KEY_1, Parcels.wrap(shop));
        bundle.putParcelable(Constants.DATA_KEY_2, Parcels.wrap(allCheckoutInfo));
        mListener.onFragmentInteraction(bundle);
    }

    @Override
    public void showProgress(final boolean show) {

    }

    @Override
    public void showError(Error error) {

    }

    private void selectedShippingAddress(UserInfo userInfo) {
        ShippingAddressResult event;
        event = new ShippingAddressResult();
        event.setUserInfo(userInfo);
        EventBus.getDefault().post(event);
    }
}
Philia answered 3/2, 2017 at 7:51 Comment(6)
It is always better to register your event bus in onResume() instead of onCreate() and unregister it in onDestroy(). If you are replacing the fragment A with fragment B. onDestroy() of fragment A will be called which will unregister the EventBus for the fragment and event will never be listen.Active
I've tried placing it in onResume() but it still doesn't work.Philia
Print a log in onDestroy of fragment A. I believe that you are replacing the fragments instead of adding, which results in invocation of onDestroy() of fragment A while moving to Fragment B. That's why Fragment A is no more registered to listen the event.Active
Yes, I am replacing the fragments, that is correct. So, then, how can I pass a value from fragment B to fragment A?Philia
Since Fragment A and Fragment B are part of same activity. You can create a variable in Activity class, so that you can save it in Fragment B and can access it from Fragment AActive
try removing EventBus.getDefault().unregister(this); from fragment A and try its working or notMina
W
15

Since you're replacing Fragment A with Fragment B, when the event is fired, Fragment A is not alive/registered to catch it. Regular events look for subscribers the moment they're fired, and then die. If there are any subscribers to that event at that time, they receive the event. This is where Sticky Events come to the rescue. Sticky Events "stick" around. Subscribers subscribing (stickly) to a sticky event after its post moment will still get it. For this do the following.

Replace EventBus.getDefault().post(event); with EventBus.getDefault().postSticky(event);

And make your ShippingAdressResult subscription sticky:

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onMessage(ShippingAddressResult event) {
    UserInfo userInfo = event.getUserInfo();
    Log.d("Tag", "Test" + userInfo);
    EventBus.getDefault().removeStickyEvent(stickyEvent); // don't forget to remove the sticky event if youre done with it
}

More Info

Warfore answered 3/2, 2017 at 8:32 Comment(0)
D
1

I think Sticky Event is what you need. If you don't have any subscriber to consume an event it will wait until it you subscribe. Which may be the your situation as you are replacing fragments.

EventBus.getDefault().postSticky(event);

If you don't need this event anymore, don't forget to remove it.

EventBus.getDefault().removeStickyEvent(stickyEvent);

Good luck!

Delftware answered 3/2, 2017 at 8:32 Comment(1)
To receive event's send in the past, the consumer also needs to subscribe with (sticky = true)Warfore

© 2022 - 2024 — McMap. All rights reserved.