Android recyclerview 在每次 activity 创建时添加重复元素
Android recyclerview adding duplicate elements on each activity creation
当我从我的导航抽屉中启动一个新片段时,它意味着将我带到一个主页,其中包含匹配配置文件的 cardView。第一次使用效果很好,我想显示的每个配置文件都在那里。但是,当我离开该片段然后再次单击它时,元素会被复制,随后每次刷新页面时,这些项目都会再次被复制。我相信这个问题出在我的 RecyclerView 适配器的某个地方,没有在 activity 创建时清除,但我无法查明它。这是我的片段 class
public class HomeFragment extends Fragment {
private CustomListAdapter listAdapter;
private static final String profileUrl = "http://10.0.2.2:3000/apip/buyers/profiles";
private static final String TAG = selectBuyerProfile.class.getSimpleName();
private ProgressDialog pDialog;
private ListView listView;
private List<BuyerProfile> buyersProfiles = new ArrayList<BuyerProfile>();
private View root;
//private RVAdapter recyclerAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_home, container, false);
return root;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
RecyclerView rv = (RecyclerView) getActivity().findViewById(R.id.rv);
//rv.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
rv.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
rv.setItemAnimator(new DefaultItemAnimator());
final RVAdapter recyclerAdapter = new RVAdapter(buyersProfiles);
rv.setAdapter(recyclerAdapter);
RequestQueue mRequestQueue;
Cache cache = new DiskBasedCache(getActivity().getCacheDir(), 1024 * 1024);
Network network = new BasicNetwork(new HurlStack());
mRequestQueue = new RequestQueue(cache, network);
mRequestQueue.start();
JsonArrayRequest profileRequest = new JsonArrayRequest(profileUrl,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
// Parsing json
for(int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
BuyerProfile parsedProfile = new BuyerProfile();
parsedProfile.setBuyerProfTitle(obj.getString("title"));
parsedProfile.setDescription(obj.getString("description"));
parsedProfile.setLocations(obj.getString("locations"));
parsedProfile.setAssetTypes(obj.getString("asset_type"));
parsedProfile.setPropertyStatuses(obj.getString("property_status"));
//parsedProfile.setBuyerId("Select");
buyersProfiles.add(parsedProfile);
} catch (Exception e) {
e.printStackTrace();
}
}
recyclerAdapter.notifyDataSetChanged();
// notifying list adapter about data changes
// so that it renders the list view with updated data
//hidePDialog();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//Toast.makeText(selectBuyerProfile.this,"Error",Toast.LENGTH_LONG).show();
}
});
mRequestQueue.add(profileRequest);
}
}
这是我的 RVAdapter class
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
private Activity activity;
private LayoutInflater inflater;
private List<BuyerProfile> profileItems;
private static boolean itemFavorited;
RVAdapter(List<BuyerProfile> profiles) {
this.profileItems = profiles;
}
public static class PersonViewHolder extends RecyclerView.ViewHolder {
TextView name;
TextView description;
TextView locations;
TextView id;
TextView investmentRangeMin;
TextView investmentRangeMax;
TextView assetTypes;
TextView propertyStatuses;
ImageView favoriteButton;
CardView cardView;
PersonViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.titleText);
description = (TextView) itemView.findViewById(R.id.descriptionText);
investmentRangeMin = (TextView) itemView.findViewById(R.id.investmentRangeMin);
investmentRangeMax = (TextView) itemView.findViewById(R.id.investmentRangeMax);
locations = (TextView) itemView.findViewById(R.id.locations);
id = (TextView) itemView.findViewById(R.id.profileNumber);
assetTypes = (TextView) itemView.findViewById(R.id.assetTypes);
propertyStatuses = (TextView) itemView.findViewById(R.id.propertyStatuses);
favoriteButton = (ImageView) itemView.findViewById(R.id.favorite_select);
cardView = (CardView) itemView.findViewById(R.id.cv);
//User selects favorite on a matched profile
itemFavorited = false;
favoriteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!itemFavorited) {
favoriteButton.setImageResource(R.drawable.ic_favorite);
//cardView.setCardBackgroundColor(R.color.colorPrimary);
itemFavorited = true;
} else {
favoriteButton.setImageResource(R.drawable.ic_favorite_border);
itemFavorited = false;
}
}
});
}
}
@Override
public int getItemCount() {
return profileItems.size();
}
@Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
@Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.name.setText(profileItems.get(i).getBuyerProfTitle());
personViewHolder.description.setText(profileItems.get(i).getDescription());
personViewHolder.locations.setText(profileItems.get(i).getLocations());
personViewHolder.assetTypes.setText(profileItems.get(i).getAssetTypes());
personViewHolder.propertyStatuses.setText(profileItems.get(i).getPropertyStatuses());
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
/*
@Override
public Object getItem(int location) {
return profileItems.get(location);
}
*/
@Override
public long getItemId(int position) {
return position;
}
}
最后是我的片段XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:padding="0dp"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Matches"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="false"
android:id="@+id/matchesText"
android:textAlignment="center"
android:textSize="20dp"
android:textColor="@color/navigationBarColor"
android:layout_alignParentStart="false"
android:layout_alignParentBottom="false"
android:layout_alignParentLeft="false"
android:layout_alignParentRight="true"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rv"
android:layout_below="@id/matchesText"
/>
<!-- Thumbnail Image -->
<ImageView
android:id="@+id/imgBillionaire"
android:src="@drawable/ic_perm_identity"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentLeft="true"
android:layout_marginRight="8dp"
android:layout_alignParentEnd="false"
android:layout_alignParentStart="true"
android:nestedScrollingEnabled="false"
android:visibility="invisible"/>
<!-- Name of Asset -->
<TextView
android:id="@+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/imgBillionaire"
android:layout_toRightOf="@+id/imgBillionaire"
android:textSize="@dimen/Title"
android:textStyle="bold" />
<!-- Description -->
<TextView
android:id="@+id/descriptionText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/titleText"
android:layout_marginTop="1dip"
android:layout_toRightOf="@+id/imgBillionaire"
android:textSize="@dimen/Description" />
<!-- Source -->
<TextView
android:id="@+id/locations"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/descriptionText"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/imgBillionaire"
android:textColor="@color/wealthsource"
android:textSize="@dimen/InvestmentRange" />
<!-- Source -->
<TextView
android:id="@+id/assetTypes"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/locations"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/imgBillionaire"
android:textColor="@color/wealthsource"
android:textSize="@dimen/InvestmentRange" />
<!-- Source -->
<TextView
android:id="@+id/propertyStatuses"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/assetTypes"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/imgBillionaire"
android:textColor="@color/wealthsource"
android:textSize="@dimen/InvestmentRange" />
<!-- Year -->
<TextView
android:id="@+id/profileNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="false"
android:layout_alignParentRight="true"
android:textColor="@color/year"
android:textSize="@dimen/Date" />
</RelativeLayout>
</LinearLayout>
知道为什么我的 recyclerview 中的项目会在每次页面刷新时不断重复吗?
可能发生的情况是,每次网络请求 returns 时,它都会尝试将每个新项目添加到片段内已经存在的列表中。
根据您实现导航逻辑的方式,您的片段不会在您导航离开后被系统销毁,而是调用一系列生命周期回调:
onPause() -> onStop() -> onDestroyView()
并且当您 return 片段时,将调用所有必需的生命周期回调,直到它达到活动状态。
onCreateView() -> onActivityCreated() -> onStart() -> onResume()
可以在此处找到有关片段生命周期工作的更多信息:https://developer.android.com/guide/components/fragments.html
由于您的片段不会被销毁和重新创建,因此您的 buyersProfiles
引用可能会保存您 return 时的先前数据。由于网络调用不会覆盖原始列表,因此每次调用 onResponse
回调时,它将从网络获取的新数据附加到现有数据旁边。
这也可能会影响您实现某种下拉刷新逻辑或刷新按钮的用例,因为新的网络调用不会清理列表。
您可以尝试避免重复的一件事是添加
buyersProfiles = new ArrayList<BuyerProfile>();
到您的 onResponse()
回调的顶部。
希望对您有所帮助。
当我从我的导航抽屉中启动一个新片段时,它意味着将我带到一个主页,其中包含匹配配置文件的 cardView。第一次使用效果很好,我想显示的每个配置文件都在那里。但是,当我离开该片段然后再次单击它时,元素会被复制,随后每次刷新页面时,这些项目都会再次被复制。我相信这个问题出在我的 RecyclerView 适配器的某个地方,没有在 activity 创建时清除,但我无法查明它。这是我的片段 class
public class HomeFragment extends Fragment {
private CustomListAdapter listAdapter;
private static final String profileUrl = "http://10.0.2.2:3000/apip/buyers/profiles";
private static final String TAG = selectBuyerProfile.class.getSimpleName();
private ProgressDialog pDialog;
private ListView listView;
private List<BuyerProfile> buyersProfiles = new ArrayList<BuyerProfile>();
private View root;
//private RVAdapter recyclerAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_home, container, false);
return root;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
RecyclerView rv = (RecyclerView) getActivity().findViewById(R.id.rv);
//rv.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
rv.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
rv.setItemAnimator(new DefaultItemAnimator());
final RVAdapter recyclerAdapter = new RVAdapter(buyersProfiles);
rv.setAdapter(recyclerAdapter);
RequestQueue mRequestQueue;
Cache cache = new DiskBasedCache(getActivity().getCacheDir(), 1024 * 1024);
Network network = new BasicNetwork(new HurlStack());
mRequestQueue = new RequestQueue(cache, network);
mRequestQueue.start();
JsonArrayRequest profileRequest = new JsonArrayRequest(profileUrl,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
// Parsing json
for(int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
BuyerProfile parsedProfile = new BuyerProfile();
parsedProfile.setBuyerProfTitle(obj.getString("title"));
parsedProfile.setDescription(obj.getString("description"));
parsedProfile.setLocations(obj.getString("locations"));
parsedProfile.setAssetTypes(obj.getString("asset_type"));
parsedProfile.setPropertyStatuses(obj.getString("property_status"));
//parsedProfile.setBuyerId("Select");
buyersProfiles.add(parsedProfile);
} catch (Exception e) {
e.printStackTrace();
}
}
recyclerAdapter.notifyDataSetChanged();
// notifying list adapter about data changes
// so that it renders the list view with updated data
//hidePDialog();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//Toast.makeText(selectBuyerProfile.this,"Error",Toast.LENGTH_LONG).show();
}
});
mRequestQueue.add(profileRequest);
}
}
这是我的 RVAdapter class
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
private Activity activity;
private LayoutInflater inflater;
private List<BuyerProfile> profileItems;
private static boolean itemFavorited;
RVAdapter(List<BuyerProfile> profiles) {
this.profileItems = profiles;
}
public static class PersonViewHolder extends RecyclerView.ViewHolder {
TextView name;
TextView description;
TextView locations;
TextView id;
TextView investmentRangeMin;
TextView investmentRangeMax;
TextView assetTypes;
TextView propertyStatuses;
ImageView favoriteButton;
CardView cardView;
PersonViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.titleText);
description = (TextView) itemView.findViewById(R.id.descriptionText);
investmentRangeMin = (TextView) itemView.findViewById(R.id.investmentRangeMin);
investmentRangeMax = (TextView) itemView.findViewById(R.id.investmentRangeMax);
locations = (TextView) itemView.findViewById(R.id.locations);
id = (TextView) itemView.findViewById(R.id.profileNumber);
assetTypes = (TextView) itemView.findViewById(R.id.assetTypes);
propertyStatuses = (TextView) itemView.findViewById(R.id.propertyStatuses);
favoriteButton = (ImageView) itemView.findViewById(R.id.favorite_select);
cardView = (CardView) itemView.findViewById(R.id.cv);
//User selects favorite on a matched profile
itemFavorited = false;
favoriteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!itemFavorited) {
favoriteButton.setImageResource(R.drawable.ic_favorite);
//cardView.setCardBackgroundColor(R.color.colorPrimary);
itemFavorited = true;
} else {
favoriteButton.setImageResource(R.drawable.ic_favorite_border);
itemFavorited = false;
}
}
});
}
}
@Override
public int getItemCount() {
return profileItems.size();
}
@Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
@Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.name.setText(profileItems.get(i).getBuyerProfTitle());
personViewHolder.description.setText(profileItems.get(i).getDescription());
personViewHolder.locations.setText(profileItems.get(i).getLocations());
personViewHolder.assetTypes.setText(profileItems.get(i).getAssetTypes());
personViewHolder.propertyStatuses.setText(profileItems.get(i).getPropertyStatuses());
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
/*
@Override
public Object getItem(int location) {
return profileItems.get(location);
}
*/
@Override
public long getItemId(int position) {
return position;
}
}
最后是我的片段XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:padding="0dp"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Matches"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="false"
android:id="@+id/matchesText"
android:textAlignment="center"
android:textSize="20dp"
android:textColor="@color/navigationBarColor"
android:layout_alignParentStart="false"
android:layout_alignParentBottom="false"
android:layout_alignParentLeft="false"
android:layout_alignParentRight="true"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rv"
android:layout_below="@id/matchesText"
/>
<!-- Thumbnail Image -->
<ImageView
android:id="@+id/imgBillionaire"
android:src="@drawable/ic_perm_identity"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentLeft="true"
android:layout_marginRight="8dp"
android:layout_alignParentEnd="false"
android:layout_alignParentStart="true"
android:nestedScrollingEnabled="false"
android:visibility="invisible"/>
<!-- Name of Asset -->
<TextView
android:id="@+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/imgBillionaire"
android:layout_toRightOf="@+id/imgBillionaire"
android:textSize="@dimen/Title"
android:textStyle="bold" />
<!-- Description -->
<TextView
android:id="@+id/descriptionText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/titleText"
android:layout_marginTop="1dip"
android:layout_toRightOf="@+id/imgBillionaire"
android:textSize="@dimen/Description" />
<!-- Source -->
<TextView
android:id="@+id/locations"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/descriptionText"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/imgBillionaire"
android:textColor="@color/wealthsource"
android:textSize="@dimen/InvestmentRange" />
<!-- Source -->
<TextView
android:id="@+id/assetTypes"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/locations"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/imgBillionaire"
android:textColor="@color/wealthsource"
android:textSize="@dimen/InvestmentRange" />
<!-- Source -->
<TextView
android:id="@+id/propertyStatuses"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/assetTypes"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/imgBillionaire"
android:textColor="@color/wealthsource"
android:textSize="@dimen/InvestmentRange" />
<!-- Year -->
<TextView
android:id="@+id/profileNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="false"
android:layout_alignParentRight="true"
android:textColor="@color/year"
android:textSize="@dimen/Date" />
</RelativeLayout>
</LinearLayout>
知道为什么我的 recyclerview 中的项目会在每次页面刷新时不断重复吗?
可能发生的情况是,每次网络请求 returns 时,它都会尝试将每个新项目添加到片段内已经存在的列表中。
根据您实现导航逻辑的方式,您的片段不会在您导航离开后被系统销毁,而是调用一系列生命周期回调:
onPause() -> onStop() -> onDestroyView()
并且当您 return 片段时,将调用所有必需的生命周期回调,直到它达到活动状态。
onCreateView() -> onActivityCreated() -> onStart() -> onResume()
可以在此处找到有关片段生命周期工作的更多信息:https://developer.android.com/guide/components/fragments.html
由于您的片段不会被销毁和重新创建,因此您的 buyersProfiles
引用可能会保存您 return 时的先前数据。由于网络调用不会覆盖原始列表,因此每次调用 onResponse
回调时,它将从网络获取的新数据附加到现有数据旁边。
这也可能会影响您实现某种下拉刷新逻辑或刷新按钮的用例,因为新的网络调用不会清理列表。
您可以尝试避免重复的一件事是添加
buyersProfiles = new ArrayList<BuyerProfile>();
到您的 onResponse()
回调的顶部。
希望对您有所帮助。