EventBus вызывается несколько раз во фрагменте ViewPager

У меня есть ViewPagerAdapter, подобный этому

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
    List<MovieCategory> movieCategoryList;

    public ViewPagerAdapter(FragmentManager fm, List<MovieCategory> movieCategoryList) {
        super(fm);
        this.movieCategoryList = movieCategoryList;
    }

    @Override
    public Fragment getItem(int position) {

        return MoviePagerFragment.start(movieCategoryList, position, "listing");

    }

    @Override
    public int getCount() {
        return movieCategoryList.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return movieCategoryList.get(position).getCategoryTitle();

    }
}

Этот ViewPagerAdapter вызывает MoviePagerFragment, используя этот статический метод в классе MoviePagerFragment.

public static Fragment start(List<MovieCategory> movieCategoryList, int position, String from) {
    Fragment moviePagerFragment = new MoviePagerFragment();
    Bundle basket = new Bundle();
    basket.putString("from",from);
    basket.putInt("viewpager-position",position);
    basket.putParcelableArrayList("movie_category_list", (ArrayList<? extends Parcelable>) movieCategoryList);
    basket.putParcelableArrayList("movie_list", (ArrayList<? extends Parcelable>) movieCategoryList.get(position).getMovies());
    moviePagerFragment.setArguments(basket);
    return moviePagerFragment;
}

Теперь я регистрирую / отменяю регистрацию EventBus, как это, в MoviePagerFragment

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

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

Затем у меня есть способ подписаться на отправленные таким образом события

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(final MovieBuyEvent event) {
    final double moviePrice = Double.parseDouble(event.getMoviesItem().getMoviePrice());
    final Dialog dialog = new Dialog(getActivity());
    dialog.setContentView(R.layout.channel_buy_dialog);
    dialog.setCancelable(true);
    ImageView imageView = (ImageView) dialog.findViewById(R.id.imageView);
    TextView tvName = (TextView) dialog.findViewById(R.id.tvName);
    Button bBuy = (Button) dialog.findViewById(R.id.bBuy);
    Button bCancel = (Button) dialog.findViewById(R.id.bCancel);
    final TextView tvPrice = (TextView) dialog.findViewById(R.id.tvPrice);
    final Spinner spinner = (Spinner) dialog.findViewById(R.id.spinner);
    Picasso.with(getActivity()).load(event.getMoviesItem().getMoviePicture()).placeholder(R.mipmap.placeholder).into(imageView);
    tvName.setText(event.getMoviesItem().getMovieName());
    tvPrice.setText(event.getMoviesItem().getMovieName());
    dialog.show();
}

MovieBuyEvent транслируется из ItemClick элемента в классе ViewHolder RecyclerViewAdapter, как это

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    public ViewHolder(View view) {
        super(view);
        itemView.setClickable(true);
        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        position = getAdapterPosition();
        MoviesItem moviesItem = moviesItemList.get(position);
        try {
            MovieBuyEvent movieBuyEvent = new MovieBuyEvent();
                movieBuyEvent.setMoviesItem(moviesItem);
                EventBus.getDefault().post(movieBuyEvent);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

Теперь проблема в том, что каждый раз, когда я пролистываю фрагмент, EventBus регистрируется и не регистрируется много раз, и поэтому

onMessageEvent(final MovieBuyEvent event)

Метод также вызывается много раз, что приводит к многократному появлению диалогового окна. Итак, где мне зарегистрировать / отменить регистрацию EventBus во фрагменте, который вызывается ViewPagerAdapter?

Как и где вы транслируете MovieBuyEvent?

Ivan Wooll 10.03.2018 12:38

Я транслирую MovieBuyEvent из прослушивателя ViewHolder onClick RecyclerViewAdapter, проверьте вопрос еще раз, я обновил код.

theanilpaudel 10.03.2018 12:49

Сколько у вас экземпляров вашего фрагмента? Он может вызываться в каждом экземпляре вашего фрагмента.

Jarik Eng 10.03.2018 13:18
0
3
1 295
3

Ответы 3

Если у вас есть несколько фрагментов, которые зарегистрировались для прослушивания трансляций MovieBuyEvent, все они будут отвечать, это понятно. Если вы зарегистрировали прослушиватель событий в действии или фрагменте, содержащем пейджер, это решило бы вашу проблему.

Вы должны переместить событие регистрации с onStart() на onCreateView(). Это потому, что onStart всегда вызывается, когда фрагмент виден пользователю.

Затем попробуйте отменить регистрацию в onDestroy():

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

Если вы никогда не использовали setOffscreenPageLimit в своем окне просмотра, вам следует ограничиться одним. По умолчанию viewpager загружает три текущих фрагмента: один, который вы видите, когда просто открываете родительский фрагмент / действие, и еще два, один за другим. Попытайтесь установитьOffscreenPageLimit равным единице при инициализации окна просмотра. Обычно он загружает по одному фрагменту за раз, а не по три каждой прокрутки вьюпейджера. Когда вы используете шину событий, она будет обращаться только к одному фрагменту за раз, а не ко всем используемым фрагментам.

Другие вопросы по теме