Android filterResults() показывает повторяющиеся элементы

Я не знаю, почему я получаю эту ошибку. Я реализовал filterResults(). На самом деле, когда я впервые ищу текст редактирования и нажимаю на него, все работает нормально. Затем, когда я возвращаюсь и снова ищу какой-то город, он показывает 2 одинаковых записи. Я добавил скриншоты. Затем, когда я возвращаюсь и ищу в третий раз, я получаю 3 одинаковых записи для каждого поискового города.

My java class:


package com.wordpress.myselfnikunj.cofighter;

import android.os.Bundle;

import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;

import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import com.wordpress.myselfnikunj.cofighter.Adapters.CountryListAdapter;
import com.wordpress.myselfnikunj.cofighter.Model.CountryNamesModel;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class AffectedCountriesFragment extends Fragment {

    EditText searchEditText;
    ListView listView;

    public static List<CountryNamesModel> countryNamesModelList = new ArrayList<>();
    CountryNamesModel countryNamesModel;
    CountryListAdapter countryListAdapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_affected_countries, container, false);

        searchEditText = (EditText) view.findViewById(R.id.searchEditText);
        listView = (ListView) view.findViewById(R.id.countriesListView);
        countryListAdapter = new CountryListAdapter(getContext(), countryNamesModelList);
//        listView.setAdapter(countryListAdapter);

        fetchData();

        searchEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                countryListAdapter.getFilter().filter(charSequence);
                countryListAdapter.notifyDataSetChanged();
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }

        });

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {

                Bundle position = new Bundle();
                position.putInt("position", i);
                Navigation.findNavController(view).navigate(R.id.action_affectedCountriesFragment_to_countryDetailsFragment, position);

            }
        });

        return view;
    }

    private void fetchData() {
        String Url = "https://corona.lmao.ninja/v2/countries/";
        RequestQueue requestQueue = Volley.newRequestQueue(getContext());
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(
                Url,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.i("hehes","entered");
                        try {
                            Log.i("hehe", response.toString());

                            for (int i = 0; i < response.length(); i++) {
                                JSONObject jsonObject = response.getJSONObject(i);
                                String countryName = jsonObject.getString("country");
                                String cases = jsonObject.getString("cases");
                                String todayCases = jsonObject.getString("todayCases");
                                String deaths = jsonObject.getString("deaths");
                                String recovered = jsonObject.getString("recovered");
                                String todayDeaths = jsonObject.getString("todayDeaths");
                                String active = jsonObject.getString("active");
                                String critical = jsonObject.getString("critical");

                                JSONObject object = jsonObject.getJSONObject("countryInfo");
                                String flagUrl = object.getString("flag");

                                countryNamesModel = new CountryNamesModel(getContext(),flagUrl, countryName, cases, todayCases, deaths, todayDeaths, recovered, active, critical);
                                countryNamesModelList.add(countryNamesModel);
                            }

                            countryListAdapter.notifyDataSetChanged();
                            listView.setAdapter(countryListAdapter);

                        }catch (Exception e) {
                            Log.i("error", e.getMessage());
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.i("errors", error.getMessage());
                        Toast.makeText(getContext(), error.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                }
        );

        requestQueue.add(jsonArrayRequest);
    }

My custom Adapter

package com.wordpress.myselfnikunj.cofighter.Adapters;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.wordpress.myselfnikunj.cofighter.AffectedCountriesFragment;
import com.wordpress.myselfnikunj.cofighter.Model.CountryNamesModel;
import com.wordpress.myselfnikunj.cofighter.R;
import com.wordpress.myselfnikunj.cofighter.UpdatesFragment;

import java.util.ArrayList;
import java.util.List;

public class CountryListAdapter extends ArrayAdapter<CountryNamesModel> {

    private Context context;
    private List<CountryNamesModel> countryModelList;
    private List<CountryNamesModel> countryModelListFiltered;

    public CountryListAdapter( Context context, List<CountryNamesModel> countryModelList) {
        super(context, R.layout.countryitem, countryModelList);
        this.context = context;
        this.countryModelList = countryModelList;
        this.countryModelListFiltered = countryModelList;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.countryitem, null, true);
        TextView tvCountryName = view.findViewById(R.id.countryName);
        ImageView imageView = view.findViewById(R.id.countryImageFlag);

        tvCountryName.setText(countryModelListFiltered.get(position).getCountry());
        Glide.with(context).load(countryModelListFiltered.get(position).getFlag()).into(imageView);

        return view;
    }

    @Override
    public int getCount() {
        return countryModelListFiltered.size();
    }

    @Nullable
    @Override
    public CountryNamesModel getItem(int position) {
        return countryModelListFiltered.get(position);
    }

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

    @NonNull
    @Override
    public Filter getFilter() {
         Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                FilterResults filterResults = new FilterResults();
                if (charSequence == null
                        || charSequence.length() == 0
                ) {
                    filterResults.count = countryModelList.size();
                    filterResults.values = countryModelList;
                } else {
                    List<CountryNamesModel> resultsModel = new ArrayList<>();
                    String searchStr = charSequence.toString().toLowerCase();

                    for (CountryNamesModel itemsModel: countryModelList) {
                        if(itemsModel.getCountry().toLowerCase().contains(searchStr)) {
                            resultsModel.add(itemsModel);
                        }
                        filterResults.count = resultsModel.size();
                        filterResults.values = resultsModel;
                    }
                }
                return  filterResults;
            }

            @Override
            protected void publishResults(CharSequence charSequence, FilterResults results) {
                countryModelListFiltered = (List<CountryNamesModel>) results.values;
                UpdatesFragment.countryNamesModelList = (List<CountryNamesModel>) results.values;
                //AffectedCountriesFragment.countryNamesModelList = (List<CountryNamesModel>) results.values;
                notifyDataSetChanged();
            }
        };
        return filter;
    }
}

Скриншоты

Второй раз

Третий раз


person NIKUNJ GARG    schedule 25.07.2020    source источник


Ответы (1)


Когда вы переходите к другому представлению фрагмента, AffectedCountriesFragment уничтожается, а public void onDestroyView() вызывается. Когда вы возвращаетесь назад, public View onCreateView вызывается снова. Но ваш фрагмент не был полностью уничтожен, и все его переменные все еще существуют и находятся в том состоянии, в котором они были оставлены.

Это означает, что когда вы переходите к следующему фрагменту, ваш countryNamesModelList остается заполненным, а когда вы возвращаетесь обратно к AffectedCountriesFragment, тот же заполненный список снова заполняется, что приводит к дублированию записей.

Что ты можешь сделать?

Отслеживайте состояние вашего фрагмента. Создайте новую переменную уровня класса private View view;, которая будет содержать представление вашего фрагмента.

    // If null - must be initialized and returned in `onCreateView`
    // If not null - must be returned in `onCreateView` immediately
    // avoiding recreation of the same view (performance improvement)
    private View view;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (view == null) {
            // Inflate the layout for this fragment ONLY IF IT IS NULL
            View view = inflater.inflate(R.layout.fragment_affected_countries, container, false);

            searchEditText = (EditText) view.findViewById(R.id.searchEditText);
            listView = (ListView) view.findViewById(R.id.countriesListView);
            countryListAdapter = new CountryListAdapter(getContext(), countryNamesModelList);
    //        listView.setAdapter(countryListAdapter);

            fetchData();

            searchEditText.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                }

                @Override
                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                    countryListAdapter.getFilter().filter(charSequence);
                    countryListAdapter.notifyDataSetChanged();
                }

                @Override
                public void afterTextChanged(Editable editable) {

                }

            });

            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {

                    Bundle position = new Bundle();
                    position.putInt("position", I);
                    Navigation.findNavController(view).navigate(R.id.action_affectedCountriesFragment_to_countryDetailsFragment, position);

                }
            });
        }

        return view;
    }

Убедитесь, что вы ничего не упускаете из понимания жизненных циклов действий и фрагментов. Вот хороший пример их жизненного цикла.

person Jenea Vranceanu    schedule 25.07.2020
comment
Эй, спасибо. Это сработало очень хорошо. Все еще изучаю фрагменты. Большое спасибо. - person NIKUNJ GARG; 25.07.2020
comment
@NIKUNJGARG, добро пожаловать! Пожалуйста, примите ответ, если он вам помог, и, при желании, проголосуйте. Спасибо! - person Jenea Vranceanu; 25.07.2020