RxJava2 (Android): PublishSubject выбрасывает только один раз в активность? - PullRequest
0 голосов
/ 26 апреля 2019

При публикации на PublishSubject в моей программе генерируется только первый опубликованный объект.Небольшой контекст моей программы:

У меня есть SomeActivity, с RecyclerView.По моему Recycler.ViewHolder у меня на клике.В методе onclick я публикую объект в PublishSubject.

В SomeActivity я подписываюсь на PublishSubject в onCreate.Когда я запускаю свое приложение, я вижу, что только первый опубликованный объект получен в SomeActivity.PublishSubject обернут в простой пользовательский «RxBus», который я использую для обмена данными в моем приложении между различными компонентами (вместо использования интерфейсов и т. Д.).

Вот как я публикую в держателе представления:

@Override
public void onClick(View v) {
    RxBus.publish(RxBus.GAME_TOUCHED, new GameEvent(data));
}

Вот как я подписываюсь в SomeActivity:

RxBus.subscribe(RxBus.GAME_TOUCHED, this, o -> {
        GameEvent gameEvent = (GameEvent) o;
        //Do something here...
    });

Вот мой "RxBus":

public final class RxBus {

    private static RxBus INSTANCE;
    private static SparseArray<PublishSubject<Object>> subjectMap = new SparseArray<>();
    private static Map<Object, CompositeDisposable> subscriptionsMap = new HashMap<>();

    public static final int GAME_TOUCHED = 7;

    @Retention(SOURCE)
    @IntDef({GAME_TOUCHED})
    @interface Subject {
    }

    private RxBus() {
    }

    public static synchronized RxBus get() {
        if (INSTANCE == null) {
            INSTANCE = new RxBus();
        }
        return INSTANCE;
    }

    @NonNull
    private static PublishSubject<Object> getSubject(@Subject int subjectCode) {
        PublishSubject<Object> subject = subjectMap.get(subjectCode);
        if (subject == null) {
            subject = PublishSubject.create();
            subject.subscribeOn(AndroidSchedulers.mainThread());
            subjectMap.put(subjectCode, subject);
        }

        return subject;
    }

    @NonNull
    private static CompositeDisposable getCompositeDisposable(@NonNull Object object) {
        CompositeDisposable compositeDisposable = subscriptionsMap.get(object);
        if (compositeDisposable == null) {
            compositeDisposable = new CompositeDisposable();
            subscriptionsMap.put(object, compositeDisposable);
        }

        return compositeDisposable;
    }

    public static void subscribe(@Subject int subject, @NonNull Object lifecycle, @NonNull Consumer<Object> action) {
        Disposable disposable = getSubject(subject).subscribe(action);
        getCompositeDisposable(lifecycle).add(disposable);
    }

    public static void unregister(@NonNull Object lifecycle) {
        CompositeDisposable compositeDisposable = subscriptionsMap.remove(lifecycle);
        if (compositeDisposable != null) {
            compositeDisposable.dispose();
        }
    }

    public static void publish(@Subject int subject, @NonNull Object message) {
        getSubject(subject).onNext(message);
    }

}

Короче говоря, подпишитесь на определенный "тип события", полученный только один раз для действия.

Есть предложения?

РЕДАКТИРОВАТЬ:

public class QuestionAdapter extends RecyclerView.Adapter<QuestionHolder> {

    private final List<Game> games = new ArrayList<>();
    private final Context context;

    public QuestionAdapter(Context context) {
        this.context = context;
    }

    @NonNull
    @Override
    public QuestionHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        QuestionHolder questionHolder = new QuestionHolder(R.layout.layout_item_question, parent);
        return questionHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull QuestionHolder holder, int position) {
        holder.bind(games.get(position));
    }

    @Override
    public int getItemCount() {
        return games.size();
    }

    public void setData(List<Game> newGames){
        games.clear();
        games.addAll(newGames);
        notifyDataSetChanged();
    }

    public void deleteItem(int position) {
        RxBus.publish(RxBus.DELETE_GAME, new GameEvent(games.get(position)));
        notifyDataSetChanged(); //restore view if not/after deleted
    }

    public Context getContext(){
        return context;
    }

}

РЕДАКТИРОВАТЬ 2:

RxBus.subscribe(RxBus.DELETE_GAME, this, o -> {
            GameEvent gameEvent = (GameEvent) o;
            Game game = gameEvent.getGame();
            MaterialDialog.Builder builder = CustomMaterialDialog.areYouSure("Delete game?", this)
                    .onNegative((dialog, which) -> dialog.dismiss())
                    .onPositive((dialog, which) -> {
                        dialog.dismiss();
                        viewModel.deleteGame(game);
                    });
            showCustomDialog(builder);
        });

РЕДАКТИРОВАТЬ 3:

Изменения в адаптере:

@Override
public void onBindViewHolder(@NonNull QuestionHolder holder, int position) {
    holder.bind(games.get(position));
    holder.getItemView().setOnClickListener(v -> {
        Game game = holder.getData();
        RxBus.publish(RxBus.GAME_TOUCHED, new GameEvent(game));
    });
}

И добавил это в видоискатель:

public View getItemView(){
    return itemView;
}
...