简体   繁体   English

Android Recycler视图切换按钮回收问题

[英]Android recycler view toggle button recycling issue

I am making an app and has a recyclerview for showing user feed. 我正在制作一个应用,并且具有用于显示用户供稿的recyclerview。 I am using a toggle button for liking posts. 我正在使用切换按钮来喜欢帖子。 When the user opens the app it enables the like button if the status is already liked by the user who is using the app and the user can also like the posts by scrolling down like other socials apps out there. 当用户打开应用程序时,如果使用该应用程序的用户已经喜欢了该状态,则启用“赞”按钮,并且该用户还可以像其他社交应用程序一样向下滚动来喜欢这些帖子。

The problem is if a toggle button is checked when scrolling down other toggle buttons belongs to other posts are also getting checked. 问题是,当向下滚动其他切换按钮所属的其他切换按钮时,是否也选中了切换按钮。

Adapter class 转接器类别

 public class topNewsAdapter extends RecyclerView.Adapter<topNewsRowHolder> {

        private ArrayList<topData> topDataList;
        private Context context;
        private Activity activity;
        private RecyclerView recyclerView;
        private View v;
        protected String liked = "success";
        protected String expired = "Expired";




        public topNewsAdapter( ArrayList<topData> listItemList , Activity activity , RecyclerView view) {

            this.topDataList = listItemList;
            this.activity = activity;
            this.recyclerView = view;

        }



        @Override
        public topNewsRowHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.top_news_row, parent, false);
            context = parent.getContext();
            return new topNewsRowHolder(v , activity); //passed activity



        }

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


            topData item = topDataList.get(position);

            if(!(item == null)) {

                holder.userName.setText(item.getUserName().toString());
                holder.timer.setText(item.getCreatedTime().toString());
                holder.status.setText(item.getStatus().toString());
                holder.fameCount.setText(item.getLikeCount().toString());
                holder.dislike_Count.setText(item.getDislike_Count().toString());
                holder.statusID.setText(item.getStatusID().toString());



                if(item.getLiked().equals(1)){
                    holder.fameButton.setChecked(true);
                }else if(item.getLiked().equals(0)){
                    holder.fameButton.setChecked(false);
                }



                if(item.getDisliked().equals(1)){
                    holder.disLikeButton.setChecked(true);

                }else if(item.getDisliked().equals(0)){
                    holder.disLikeButton.setChecked(false);
                }





               holder.fameButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        if(isChecked){

                           lRequester(holder.statusID.getText().toString() , "1" , holder.fameCount );
                            dRequester(holder.statusID.getText().toString() , "0" , holder.dislike_Count);

                            holder.fameButton.setChecked(true);


                       }else if(!isChecked){
                            lRequester(holder.statusID.getText().toString() , "0" , holder.fameCount);


                        }
                   }
               });


                holder.disLikeButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        if(isChecked){
                            dRequester(holder.statusID.getText().toString(), "1" ,holder.dislike_Count);
                            lRequester(holder.statusID.getText().toString() , "0" , holder.fameCount);

                            holder.fameButton.setChecked(false);

                        }else if(!isChecked){
                            dRequester(holder.statusID.getText().toString() , "0" , holder.dislike_Count);
                        }
                    }
                });







        }



        }













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


        @Override
        public long getItemId(int position) {
            return position;
        }




        public void lRequester(String id , String type, final TextView textview){
            Call<responseFD> request = handler.handlerClass.fame(data("u") , data("t") , id , type );
            request.enqueue(new Callback<responseFD>() {
                @Override
                public void onResponse(Call<responseFD> call, Response<responseFD> response) {
                    if(!response.body().getResponse().isEmpty() && (response.body().getResponse() != null)) {

                        if (response.body().getResponse().equals(expired)) {
                            vlData.getInstance().terminateRunnable();
                            reset();

                        }else if (response.body().getResponse().equals(liked)) {
                            textview.setText(response.body().getLike_count().toString());

                        }


                    }

                }

                @Override
                public void onFailure(Call<responseFD> call, Throwable t) {
                    Toast.makeText(v.getContext(), "Something Gone Wrong", Toast.LENGTH_SHORT).show();

                }
            });


        }


        public void dRequester(String id , String type , final TextView textView){
            Call<responseFD> request = handler.handlerClass.disfame(data("u") , data("t") , id , type );
            request.enqueue(new Callback<responseFD>() {
                @Override
                public void onResponse(Call<responseFD> call, Response<responseFD> response) {
                    if(!response.body().getResponse().isEmpty() && response.body().getResponse() != null) {
                        if (response.body().getResponse().equals(expired)) {
                            vlData.getInstance().terminateRunnable();
                            reset();

                        }else if (response.body().getResponse().equals(liked)) {
                            textView.setText(response.body().getDislike_Count().toString());

                        }
                    }


                }

                @Override
                public void onFailure(Call<responseFD> call, Throwable t) {
                    Log.d("data", "onFailure: " + t.getMessage());
                }
            });







        }


        public void reset(){

            Intent i = new Intent(activity , login.class);
            activity.startActivity(i);
            activity.finish();
        }



    }

Rowholder class 行持有人类

 public  class topNewsRowHolder extends RecyclerView.ViewHolder {

    protected TextView userName;
    protected TextView timer;
    protected TextView status;
    protected ImageView profilePicHolder;
    protected TextView fameCount;
    protected TextView dislike_Count;
    protected ToggleButton fameButton;
    protected ToggleButton disLikeButton;
    protected View v;
    protected TextView statusID;
    protected Activity activity;
    protected RelativeLayout holderlayout;




    public topNewsRowHolder(View view , Activity activity ){
        super(view);
        v = view;
        this.activity = activity;

        this.userName = (TextView)view.findViewById(R.id.usernameHolder);
        this.timer = (TextView)view.findViewById(R.id.timeHolder);
        this.status = (TextView)view.findViewById(R.id.status_user);
        this.profilePicHolder = (ImageView)view.findViewById(R.id.profile_pic_holder);
        this.fameCount = (TextView)view.findViewById(R.id.like_count);
        this.dislike_Count = (TextView)view.findViewById(R.id.dislike_count);
        this.fameButton = (ToggleButton)view.findViewById(R.id.fameButton);
        this.disLikeButton = (ToggleButton)view.findViewById(R.id.dislikeButton);
        this.statusID = (TextView)view.findViewById(R.id.statusID);
        this.holderlayout = (RelativeLayout) view.findViewById(R.id.text);







    }


    }

I know this is because of the recycling. 我知道这是因为回收。 How to fix this issue ?. 如何解决此问题? Thanks :) 谢谢 :)

Try this : RecyclerView needs an external variable to keep track of which items are checked, while SparseBooleanArray will work, its tedious. 尝试以下操作:RecyclerView需要一个外部变量来跟踪检查了哪些项目,而SparseBooleanArray可以工作,但很麻烦。

holder.fameButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean IsChecked) { 
        isChecked ? item.setIsLiked(1) : item.setIsLiked(0);
        if(isChecked){
            lRequester(holder.statusID.getText().toString() , "1" , holder.fameCount );
            dRequester(holder.statusID.getText().toString() , "0" , holder.dislike_Count);
        } else if(!isChecked){
            lRequester(holder.statusID.getText().toString() , "0" , holder.fameCount);
        }
        }
     });

Create a Broker pattern for managind likes within the content feed. 在内容供稿中为喜欢的人创建经纪人模式。

This singleton broken would keep track of each Content feed item id and map it to a state (social or just likes) in a hashmap. 打破此单例将跟踪每个Content feed项ID,并将其映射到哈希图中的状态(社交或喜欢)。 And every time there is a reaction (like/unlike/dislike/undislike) happenning to a Content feed item, you trigger the actian using this Broker that also propagates and keeps track of the changes locally. 每次对内容供稿项目发生反应(喜欢/不喜欢/不喜欢/不喜欢)时,您都可以使用此Broker触发actian,该Broker也可以在本地传播并跟踪更改。 You ahould implement a Broadcaster or a pub-sub pattern to ibform the UI about the changes. 您应该实现一个Broadcaster或pub-sub模式以使UI关于更改。

Preferably use a Content Provider with a database for storing the json you are getting from the webserver. 最好将Content Provider与数据库一起使用,以存储您从Web服务器获取的json。

Let me know if you need further clarifications. 让我知道是否需要进一步说明。


SocialBroker.java SocialBroker.java

public class SocialBroker extends ISocialBroker {
    //region <!-- Private properties -->
    private static SocialBroker _instance;
    private HashMap<UUID, SocialStatus> _map = new HashMap<>();
    //endregion

    //region <!-- Singleton initializer -->
    public static SocialBroker newInstance() {
        if (_instance == null) {
            _instance = new SocialBroker();
        }
        return _instance;
    }

    private SocialBroker() {};
    //endregion
    // The interface method implemented here
}

ISocialBroker.java ISocialBroker.java

public interface ISocialBroker {
    public synchronized SocialStatus save(String expiresAt, UUID id, boolean hasLiked, int numberOfLikes, int numberOfComments);
    public SocialStatus lookup(UUID id);
    public synchronized SocialStatus like(UUID id);
    public synchronized SocialStatus unlike(UUID id);

    public HashMap<UUID, SocialStatus> getMap();
    public void loadState(HashMap<UUID, SocialStatus> restoredSocialState);
}

OnReactionObserver.java OnReactionObserver.java

public interface OnReactionObserver {
    void onLikeReaction();
}

OnReactionPublisher.java OnReactionPublisher.java

public interface OnReactionPublisher {
    void attachObserver(OnReactionObserver... observer);
    void notifyListeners();
}

When you bind the results to your views in your adapter, you save the entries using the broker, then in your like button view, you summon the Broker again to execute the like/unlike/dislike/undislike. 将结果绑定到适配器中的视图时,可以使用代理保存条目,然后在“喜欢”按钮视图中再次召集代理以执行“喜欢/不喜欢/不喜欢/不喜欢”。

SocialStatus is just a model to keep track of information, that can be serialized, saved, synchronized with an online service. SocialStatus只是跟踪信息的模型,可以与在线服务进行序列化,保存和同步。

Hope this points you to the right direction. 希望这为您指明正确的方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM