Search code examples
androidlistviewcheckbox

Android setOnCheckedChangeListener runs twice


This is my code. What can ba a cause?

holder.favorite.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                addFavorite(famous);
            } else {
                deleteFavorite(famous);
            }
        }
    });

When isChecked=true, firstly is run addFavorite() and after that deleteFavorite().

When isChecked=false, firstly is run deleteFavorite() and after that addFavorite().

Don't know why...

EDIT: When I scroll down/up my ListView it calls these methods too... Weird...

    private void deleteFavorite(final FamousTop40Ranking famous) {
        DeleteFavoriteData data = new DeleteFavoriteData(famous.getId());
        FavoriteDeleteApi.Factory.getInstance().deleteFavorite(data.getData())
                .enqueue(new Callback<StatusInfoModel>() {
                    @Override
                    public void onResponse(Call<StatusInfoModel> call, Response<StatusInfoModel> response) {
                        showToast(mActivity, "Famous deleted from your Favorites list.");
                        famous.setFollowersCountry(famous.getFollowersCountry() - 1);
                        famous.setFollowersWorld(famous.getFollowersWorld() - 1);
                        notifyDataSetChanged();
                    }

                    @Override
                    public void onFailure(Call<StatusInfoModel> call, Throwable t) {
                        Log.d("deleteFavorite", mActivity.getString(R.string.something_went_wrong) + t.getMessage());
                    }
                });
    }




private void addFavorite(final FamousTop40Ranking famous) {
        FavoriteCountApi.Factory.getInstance().countFavorites()
                .enqueue(new Callback<CountFavoriteModel>() {
                    @Override
                    public void onResponse(Call<CountFavoriteModel> call, Response<CountFavoriteModel> response) {
                        if (response.isSuccessful()) {
                            if (response.body().getCount() < 20) {
                                FavoriteAddApi.Factory.getInstance().addFavorite(String.valueOf(famous.getId()))
                                        .enqueue(new Callback<StatusInfoModel>() {
                                            @Override
                                            public void onResponse(Call<StatusInfoModel> call, Response<StatusInfoModel> response) {
                                                showToast(mActivity, "Famous added from your Favorites list.");
                                                famous.setFollowersCountry(famous.getFollowersCountry() + 1);
                                                famous.setFollowersWorld(famous.getFollowersWorld() + 1);
                                                notifyDataSetChanged();
                                            }

                                            @Override
                                            public void onFailure(Call<StatusInfoModel> call, Throwable t) {
                                                Log.d("addFavorite", mActivity.getString(R.string.something_went_wrong) + t.getMessage());
                                            }
                                        });
                            } else {
                                showToast(mActivity, mActivity.getString(R.string.reached_max_favorites));
                            }
                        }
                    }

                    @Override
                    public void onFailure(Call<CountFavoriteModel> call, Throwable t) {
                        Log.d("countFavorite", mActivity.getString(R.string.something_went_wrong) + t.getMessage());
                    }
                });
    }

getView() method:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;

    if(convertView == null) {
        LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_view_ranking_famous_single_item, parent, false);
    }

    final FamousTop40Ranking famous = famousModelList.get(position);

    holder = new ViewHolder(convertView);

    holder.name.setText(famous.getName());
    if (mTab == 0) { // RankingFamousMainFragment.TAB_FAMOUS
        holder.followers.setText(String.valueOf(famous.getFollowersWorld()));
    } else {
        holder.followers.setText(String.valueOf(famous.getFollowersCountry()));
    }

    if (famous.getIsFavorite().get(0).getFavorite().equals("1")) {
        holder.favorite.setChecked(true);
    } else {
        holder.favorite.setChecked(false);
    }

    Glide
            .with(mActivity)
            .load(famous.getPhoto())
            .fallback(R.drawable.bg_gradient)
            .error(R.drawable.bg_gradient)
            .centerCrop()
            .crossFade()
            .into(holder.photo);

    holder.favorite.setOnCheckedChangeListener(null);
    holder.favorite.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                addFavorite(famous);
            } else {
                deleteFavorite(famous);
            }
        }
    });

    convertView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showToast(mActivity, mActivity.getString(R.string.famous_clicked, position));
        }
    });

    return convertView;
}

Solution

  • In getView. Move setonCHecked(null) before the if/else.

    The reason this is hapening is getView might get called alot of times, in this case i think it is called because when you change state(check/uncheck) it redraws the button. And in your getView you are calling setChecked which triggers the listener. Setting the listener to null before calling holder.favorite.setChecked(true/false) wont double trigger it.

    About up/down issue- It is the same, when the view is of the screen it is deleted. When it appears again it calls getView whichi triggers everything due to holder.favorite.setChecked(true) activating the onCheckChangedLIstener

    As an example:

    holder.favorite.setOnCheckedChangeListener(null);
    holder.favorite.setChecked(true);
    holder.favourite.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                // handle your logic
            }
        });