用户交互后如何根据 RecyclerView 适配器内部服务器的响应更新 TextView?

Posted

技术标签:

【中文标题】用户交互后如何根据 RecyclerView 适配器内部服务器的响应更新 TextView?【英文标题】:How to update TextView based on response from server inside RecyclerView adapter after user interaction? 【发布时间】:2020-01-22 18:03:00 【问题描述】:

我试图通过读取来自服务器的响应来确定用户是否喜欢帖子,在 Retrofit.call.enqueue() 中将值相应地分配给布尔值,如果为真,则将 UI 的 TextView 值更改为 +1。如何在多个回调中保存变量的值并在调用完成后根据它更新 UI?

在 UI 中,我在 RecyclerView 适配器中有两个按钮(喜欢\不喜欢),点击后将数据更新到 mysql 数据库,我试图在用户交互后更新喜欢或不喜欢的数量(如果用户尚未投票,则 +1,我通过改造电话检查)。

我试图在适配器类中为全局变量赋值,但是代码 在调用完成之前运行(我认为这是因为 Retrofit 默认在单独的线程中运行)。 我还尝试在 onPostExecute() 方法中更新 AsyncTask 中的 UI,如下所示:

private class LoadDataAsyncTask extends AsyncTask<String, Void, Boolean> 

        //variable to be updated based on response
        boolean voted = true;

        public LoadDataAsyncTask() 
            //todo
        

        @Override
        protected Boolean doInBackground(String... params) 

            Log.v("Voted state start", String.valueOf(voted));
            GetUserVotes mApiGetUserVotes;
            mApiGetUserVotes = ApiUtils.getAPIServiceUserVotes();
            mApiGetUserVotes.getVotes().enqueue(new Callback<ResultVotes>() 
                    @Override
                    public void onResponse(Call<ResultVotes> call, Response<ResultVotes> response) 
                        if(response.body().getSuccess()==1)
                            voted = true;
                        else
                            voted = false;
                        if(!voted)
                            //todo
                         else 
                            Log.v("Voted", String.valueOf(voted));
                            //todo
                        
                    

                    @Override
                    public void onFailure(Call<ResultVotes> call, Throwable t) 

                    
                );
            Log.v("Voted state end", String.valueOf(voted));
            return voted;
        

        @Override
        protected void onPostExecute(Boolean result) 
            Log.v("Voted state", String.valueOf(result));
            if(result) 
                //todo

             else 
                //update UI TextView to +1 vote
                Log.v("onPostExecution", "Triggered");
            
        

    

结果是:

1. V/Voted state start: false
2. V/Voted state end: false
3. V/Voted state: false
4. V/onPostExecution: Triggered
5. V/Voted: true

并且应该看起来像(如果投票):

1. false
2. true
3. true
4. Triggered
5. true

我也尝试过这样的界面:

public interface ResponseListener 

    void onSuccess();

    void onFail();

并在 Adapter 类中实现它(onFail() 如果没有投票):

 @Override
    public void onBindViewHolder(final NewsViewHolder holder, int position) 

        final int iLikes = list.get(position).getPositiveVotes();
        final int iDislikes = list.get(position).getNegativeVotes();
        final ResponseListener retrofitResponseListener = new ResponseListener() 
            @Override
            public void onSuccess() 

            

            @Override
            public void onFail() 
                int x = iNegativeVotes + 1;
                holder.textViewDislike.setText(String.valueOf(x));
            
        ;

    

这里是代码sn-p:

 @Override
    public void onBindViewHolder(final NewsViewHolder holder, int position) 

        final int iLikes = list.get(position).getPositiveVotes();
        final int iDislikes = list.get(position).getNegativeVotes();

        holder.btnPositive.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                final boolean[] voted = false;
                GetUserVotes mApiGetUserVotes;
                mApiGetUserVotes = ApiUtils.getAPIServiceUserVotes();
                mApiGetUserVotes.getVotes(email, url).enqueue(new Callback<ResultVotes>() 
                    @Override
                    public void onResponse(Call<ResultVotes> call, Response<ResultVotes> response) 
                        if(response.body().getSuccess()==1)
                            voted[0] = true;
                        else voted[0] = false; 
                        if(!voted[0])
                            //this is not working
                            holder.textViewDislike.setText(String.valueOf(x));
                         else 
                            //do not update TextView
                        
                    

                    @Override
                    public void onFailure(Call<ResultVotes> call, Throwable t) 

                    
                );
            
        );
    

如何根据 Retrofit 响应在单击按钮后更新 TextView 值?

听说有一种叫做“回调地狱”的东西,它是什么,如何有效避免?

【问题讨论】:

【参考方案1】:

你不需要任何全局变量,也不需要回调。

刚刚在您的适配器中声明了一个公共方法,它只是更新您的适配器列表。您只需要更新项目的位置。

更新点赞:

public void updateLikes(int pos)
   int iLikes = list.get(position).getPositiveVotes();
   iLikes++;
   list.get(position).setPositiveVotes(iLikes);
   notifyDataSetChanged();  // very important 


更新不喜欢:

public void updateDislikes(int pos)
   int iDislikes = list.get(position).getNegativeVotes();
   iDislikes ++;
   list.get(position).setNegativeVotes(iDislikes);
   notifyDataSetChanged();  // very important 


在您的改造或 Aysn 成功调用中,只需调用这些方法:

adapter.updateLikes(position) or adapter.updateDislikes(position)

【讨论】:

这与我在点击后为按钮实现的动画系统冲突。我在片段中持有类模型值: Fragment.list.get(holder.getAdapterPosition()).setTrueBtnClicked(!Fragment.list.get(holder.getAdapterPosition()).isTrueBtnClicked);出现错误 java.lang.ArrayIndexOutOfBoundsException: length=109;索引=-1 @IvanZ。我没听懂?

以上是关于用户交互后如何根据 RecyclerView 适配器内部服务器的响应更新 TextView?的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView(自定义适配器)不刷新搜索列表

如何根据类别实现带有节头的RecyclerView?

如何将两个适配器设置为一个 RecyclerView?

如何在 RecyclerView 适配器中的 ClickListener 上显示 AlertDialog

如何给recyclerView瀑布流设置均等间距

如何给recyclerView瀑布流设置均等间距