活动/片段中的警报对话框确认后,如何在单击时更新RecyclerView按钮状态?

时间:2019-08-02 19:09:27

标签: java android android-recyclerview broadcastreceiver recycler-adapter

我有一个非常独特的情况,我在recyclerview中有一个按钮,单击该按钮(初始状态为“ register”)后,会将意图传递给片段或活动中的广播接收器,并在其中引发警报对话框,其中2选项,是或否。如果选择否,则什么也不会发生,并且对话框消失,但是如果单击是,它将处理我在我的演示者类中定义的功能(与数据有关),并且应该将我的按钮ui状态更新为“取消”。其他方法也一样,单击“取消”将返回警报,单击“是”将切换ui文本进行注册。

现在我已经实现了如下代码(请注意,即使notifydatasetchanged对我也不起作用)。知道我做错了什么以及如何实现吗? 适配器中public void onBind(int position)函数中的代码:

if (repo.getIsRsvpAvailable().equals("true")) {
    rsvpButton.setVisibility(View.VISIBLE);
    for (int i = 0; i < mAllRSVPEventsList.size(); i++) {
        if (mAllRSVPEventsList.get(i).getEvent().getEventId().equals(repo.getEventId()) && mAllRSVPEventsList.get(i).getIsAttending()) {
            rsvpButton.setText("CANCEL");
            rsvpButton.setOnClickListener(v -> {
                Intent in = new Intent("main_rsvp_button_clicked");
                in.putExtra("main_rsvp_event_id", repo.getEventId());
                in.putExtra("main_rsvp_is_attending", "false");
                in.putExtra("main_rsvp_item_position", position);
                rsvpButton.getContext().sendBroadcast(in);
            });
            break;
        } else {
            rsvpButton.setText("RSVP");
            rsvpButton.setOnClickListener(v -> {
                Intent in = new Intent("main_rsvp_button_clicked");
                in.putExtra("main_rsvp_event_id", repo.getEventId());
                in.putExtra("main_rsvp_is_attending", "true");
                in.putExtra("main_rsvp_item_position", position);

                rsvpButton.getContext().sendBroadcast(in);
            });
        }
    }

}

这是我的活动中广播接收器中的相应代码:

private BroadcastReceiver mEventIdReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            String eventId = intent.getStringExtra(EVENTID_MAIN_EXTRA_TITLE);
            String isAttending = intent.getStringExtra(EVENTID_MAIN_IS_ATTENDING);
            int itemPosition = intent.getIntExtra(EVENTID_MAIN_RSVP_ITEM_POSITION, 0);


            if (isAttending.equals("true")) {
                showDialog(R.string.rsvp_title, R.string.confirm_rsvp_body, R.string.yes,
                        (dialog, which) -> {
                            mPresenter.onRSVPClick(eventId, isAttending);

                            mEventListAdapter.notifyDataSetChanged();
                            mEventRecyclerView.removeAllViews();
                            mEventRecyclerView.scrollToPosition(itemPosition);

                        }, R.string.no, null, null);
            } else {
                showDialog(R.string.rsvp_title, R.string.confirm_cancel_body, R.string.yes,
                        (dialog, which) -> {
                            mPresenter.onRSVPClick(eventId, isAttending);

                            mEventListAdapter.notifyDataSetChanged();
                            mEventRecyclerView.removeAllViews();
                            mEventRecyclerView.scrollToPosition(itemPosition);

                        }, R.string.no, null, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
};

请注意:mEventListAdapter是我的适配器,我正在使用按钮UI代码,而mEventRecyclerView是我在片段中使用的回收器视图。

知道我丢失或做错了什么吗? 谢谢!

RSVPClick方法:

@Override
public void onRSVPClick(String eventId, String isAttending) {
    getMvpView().showLoading();
    getCompositeDisposable().add(getDataManager()
            .doRSVPEventApiCall(
                    eventId,
                    getDataManager().getFirstName(),
                    getDataManager().getLastName(),
                    getDataManager().getCurrentUserEmail(),
                    isAttending
            )
            .subscribeOn(getSchedulerProvider().io())
            .observeOn(getSchedulerProvider().ui())
            .subscribe(response -> {
                if (!isViewAttached()) {
                    return;
                }
                getMvpView().hideLoading();
            }, throwable -> {
                if (!isViewAttached()) {
                    return;
                }
                getMvpView().hideLoading();
                if (throwable instanceof ANError) {
                    ANError anError = (ANError) throwable;
                    handleApiError(anError);
                }
            }));
}

5 个答案:

答案 0 :(得分:3)

您可以轻松维护一个数组,以指示RecyclerView中每个项目的按钮状态。例如,假设每个按钮有两种状态(即RSVP = 0,Cancel = 1)。现在,在RecyclerView适配器中声明一个数组,如下所示。

private int[] stateArray; 

在适配器的构造函数中,如下所示初始化数组。让我们假设您的构造函数如下所示。

public EventListAdapter(Context context, ArrayList<Event> eventList) {
    this.eventList = eventList; 
    stateArray = new int[eventList.size];
    initializeTheStateArray(eventList);
}

private void initializeTheStateArray(ArrayList<Event> eventList) {

    // Initialize the array so that we can keep track of the items which are being attended or not. 
    for (int i = 0; i < eventList.size(); i++) {
        if(event.isAttending()) stateArray[i] = 1;
        else stateArray[i] = 0;
    }
}

现在,在onBindViewHolder函数中,根据stateArray的条目设置按钮的文本。这看起来应如下所示。

if(stateArray[position] == 1) button.setText("Cancel"); // Because this item is already registerd 
else button.setText("RSVP");

您的适配器需要一些附加功能,以便您可以在单击按钮时更新stateArray或从API更新。

public void updateButtonState(int position, boolean isAttendening) {
    if(isAttending) stateArray[position] = 1;
    else stateArray[position] = 0;
    notifyDataSetChanged(); // Call the notifyDataSetChanged here to see the affect
}

并且在API调用之后更新适配器的整个列表时,也请不要忘记更新stateArray。我希望您已经有一个功能来更新适配器中的事件列表。如下修改功能。

public void updateEventList(ArrayList<Event> eventList) {
    this.eventList = eventList;
    stateArray = new int[eventList.size()];
    initializeTheStateArray(eventList);
}

现在,单击按钮时,可以调用适配器的updateButtonState功能。在rsvpButton.setOnClickListener中修改按钮单击操作。

如果需要,还可以修改onReceive函数,以在RecyclerView中获得预期的输出。

希望此设置将帮助您实现所需的预期行为。

最后但并非最不重要的一点是,在onReceive函数中,由于网络调用是异步的,因此如果RecyclerViewRecyclerView的项目没有影响,您将立即对其进行更新。并需要一些时间才能从API提取数据。当API调用中的数据可用时,您可以考虑从updateEventList方法中调用onRSVPClick方法。

希望有帮助!

答案 1 :(得分:2)

我认为这可能会有所帮助:

  1. onBindViewHolder()中的按钮上设置点击侦听器。
  2. 在您的点击监听器调用notifyItemChanged(position)
  3. 在适配器中维护一些状态,以处理何时更改按钮状态的逻辑,例如,在onClick中包含一个变量,您可以将其标记为shouldChangeState = true
  4. 再次调用onBindViewHolder()时,请检查此状态并进行绑定,就像通常只处理这种情况并相应地更改TextView一样。 button.setVisibility(..)button.text = "My New Text"

在onBindViewholder内部:

 holder.myRow.setOnClickListener(v -> {
          notifyItemChanged(position) 
 }

好的,所以要在onBindViewHolder中处理您的持有人(对不起,科特林):

创建您的视图持有人。

sealed class MyListViewHolder(view: View) : RecyclerView.ViewHolder(view)

class MyListItemViewHolder(view: View) : MyListViewHolder(view) {
    val name: TextView = view.my_name
    val myDetail: TextView = view.my_detail
    val myOtherDetail: TextView = view.my_other_detail
}

在创建时:

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyListViewHolder {
        val inflater: LayoutInflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.row_item, parent, false)
        val viewHolder = MyListItemViewHolder(view)

        with(view) {
            tag = viewHolder
        }
        return viewHolder
    }

然后在onBindViewHolder中:

  override fun onBindViewHolder(itemHolder: MyListViewHolder, position: Int) {
        val holder = itemHolder as MyListItemViewHolder
        val currentInfo = myList[position]

        // Get your data from list to bind here.

        holder.name.text = // Text
        holder.myDetail.text = // Text
        holder.myOtherDetail.text = Text

        holder.setOnClickListener {
             // Other stuff, state, actions etc.
             notifyItemChanged(position)
        }
    }

答案 2 :(得分:2)

实际更改数据集后,应调用

notifyDatasetChanged()。正如Sudhanshu Gupta指出的,notifyDatasetChanged()在错误的时间(单击对话框按钮时)被调用。由于适配器中的mEventListResponseListmAllRSVPEventsList是私有的,因此更改它们的唯一方法是调用addItems()addRSVPItems()方法。显然,在单击对话框按钮时,这些方法均未调用,表明数据集未更改。因此notifyDatasetChanged()无效。

  

更新可能需要几秒钟。但无论是否更新,一旦出现警报并单击“是”,是否可以将适配器中按钮的ui更改为其他状态(例如从rsvp取消)

否,由于上述原因。

并且,当响应到达时,除了日志记录外,它都将被丢弃。 Presenter类的onRSVPClick()中的代码段。

.subscribe(response -> {
    if (!isViewAttached()) {
        return;
    }
    Log.d("rsvptest", "basic event id:" + response);

    getMvpView().hideLoading();

}

要查看更改,您应该通过公开合适的方法并以到达的响应中的数据进行调用来以某种方式更新适配器中的mEventListResponseListmAllRSVPEventsList。另外,不要忘记也使用该方法调用notifyDatasetChanged()

答案 3 :(得分:2)

因此,我能够给出一个答案,而且非常简单。

这是答案:

if (repo.getIsRsvpAvailable().equals("true")){
    rsvpButton.setVisibility(View.VISIBLE);
    if(mAllRSVPEventsList.size() != 0) {

        for (int i = 0; i < mAllRSVPEventsList.size(); i++) {
            if (mAllRSVPEventsList.get(i).getEvent().getEventId().equals(repo.getEventId()) && mAllRSVPEventsList.get(i).getIsAttending()) {
                rsvpButton.setText("CANCEL");
                rsvpButton.setTextColor(Color.parseColor("#647ed6"));
                mYesText.setVisibility(View.VISIBLE);
                rsvpButton.setBackgroundColor(Color.WHITE);
                GradientDrawable gd = new GradientDrawable();
                gd.setCornerRadius(2);
                gd.setGradientRadius(2);
                gd.setStroke(2, 0xFF647ed6);
                rsvpButton.setBackground(gd);
                rsvpButton.setOnClickListener(v -> {
                    Log.d("clickedbutton", "it is in" + repo.getTitle());
                    mCallback.onRSVPButtonClick(repo.getEventId(), position, "false", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

                });
                break;
            }

            if (mAllRSVPEventsList.get(i).getEvent().getEventId().equals(repo.getEventId()) && !mAllRSVPEventsList.get(i).getIsAttending()) {

                rsvpButton.setText("RSVP");
                rsvpButton.setBackgroundColor(Color.parseColor("#647ed6"));
                rsvpButton.setTextColor(Color.WHITE);
                mYesText.setVisibility(View.GONE);

                rsvpButton.setOnClickListener(v -> {

                    mCallback.onRSVPButtonClick(repo.getEventId(), position, "true", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

                });
                break;
            } else {
                rsvpButton.setText("RSVP");
                rsvpButton.setBackgroundColor(Color.parseColor("#647ed6"));
                rsvpButton.setTextColor(Color.WHITE);
                mYesText.setVisibility(View.GONE);
                rsvpButton.setOnClickListener(v -> {
                    mCallback.onRSVPButtonClick(repo.getEventId(), position, "true", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

                });
            }


        }
    } else {
        for (int i = 0; i < mEventListResponseList.size(); i++) {
            rsvpButton.setOnClickListener(v -> {
                mCallback.onRSVPButtonClick(repo.getEventId(), position, "true", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

            });
        }
    }
}

因此,基本上,我必须分离出if循环,以便ui刷新后根据条件进行更新。每次都可以正常工作,并且会检查rsvp列表的大小是否为0(如果为0)(默认设置为rsvp,单击该按钮将其切换为UI中的取消按钮),它将事件添加到rsvp列表中因此,下次我进行迭代时,有一个事件需要反复检查。感谢所有尝试提供帮助的人,所有回答的人+10!感谢您的帮助。

答案 4 :(得分:1)

您是否在调用notifyDatasetChanged()之前根据对话框上用户选择的操作更新了 repo 对象? 看来doRSVPEventApiCall()方法不会更新适配器可用的项目列表,因此notifyDatasetChanged()无效。