英文:
Android filterResults() showing duplicate items
问题
我不知道为什么会出现这个错误。
我已经实现了 `filterResults()`。
实际上,当我第一次在编辑文本中进行搜索并点击时,它可以正常工作。
然后,当我回来再次搜索一些城市时,它会显示两个相同的条目。我已经添加了截图。
然后,当我回来第三次搜索时,对于每个搜索的城市,我得到了3个相同的条目。
我的Java类:
...
我的自定义适配器:
...
**截图**
[第二次搜索](https://user-images.githubusercontent.com/67901968/88452218-8c18f800-ce7a-11ea-9477-ebcd45070bad.jpg)
[第三次搜索](https://user-images.githubusercontent.com/67901968/88452216-89b69e00-ce7a-11ea-8442-be9e8de3be7e.jpg)
英文:
I don't know why I am getting this error.
I had implemented filterResults()
.
Actually, when I search first time in edit text and click on it, it works fine.
Then when I come back and search for some city again, it shows 2 same entries. I have added screenshots.
Then when I come back and search 3rd time I got 3 same entries for each city searched.
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;
}
}
Screenshots
答案1
得分: 0
当您导航到AffectedCountriesFragment
的另一个片段视图时,该片段将被销毁,public void onDestroyView()
方法将被调用。当您返回时,public View onCreateView
方法将被再次调用。但是您的片段并没有完全销毁,所有的变量仍然存在,并且处于它们离开时的状态。
这意味着当您导航到下一个片段时,您的countryNamesModelList
保持填充状态,当您返回到AffectedCountriesFragment
时,同样的填充列表会再次被填充,导致条目重复。
您可以做什么?
跟踪片段的状态。创建一个新的类级变量private View view;
来保存片段的视图。
// 如果为null - 必须在`onCreateView`中初始化并返回
// 如果不为null - 必须立即在`onCreateView`中返回
// 避免重新创建相同的视图(提高性能)
private View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view == null) {
// 仅在视图为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;
}
确保您在了解Activity和Fragment生命周期方面没有遗漏任何内容。这里有一个很好的例子关于它们的生命周期。
英文:
When you navigate to another fragment view of the AffectedCountriesFragment
getting destroyed and public void onDestroyView()
is called. When you return back public View onCreateView
is called again. But your fragment was not totally destroyed and all of its variables still exist and are in the state they were left.
It means that when you navigate to the next fragment your countryNamesModelList
stays filled and when you return back to the AffectedCountriesFragment
the same filled list getting filled again resulting in duplicated entries.
What you can do?
Track the state of your fragment. Create a new class-level variable private View view;
that will hold the view of your fragment.
// 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;
}
Make sure you are not missing something in an understanding of Activity and Fragment lifecycles. Here is a good example of their lifecycles.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论