Reputation: 69
When I launch a new fragment from my navigation drawer, it's meant to take me to a home page with a cardView of matching profiles. It works great the first time and every profile I want to show up is there. However, when I navigate away from the fragment and then click on it again, the elements are duplicated, and each subsequent time I refresh the page the items are duplicated once more. I believe this problem lies somewhere in my RecyclerView adapter not clearing on an activity create, but I have't been able to pinpoint it. Here's my fragment 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);
}
}
And here is my 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;
}
}
Finally here is my fragments 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>
Any ideas why the items in my recyclerview would keep duplicating on each page refresh?
Upvotes: 1
Views: 3303
Reputation: 486
What can possibly be happening is that each time the network request returns, it tries to add every new item to an already existing list inside the fragment.
Depending on how you implement your navigation logic, your fragment won't be destroyed by the system once you navigate away from it, instead calling a series of lifecycle callbacks:
onPause() -> onStop() -> onDestroyView()
And when you return to the fragment, all required lifecycle callbacks will be called until it reaches the active state.
onCreateView() -> onActivityCreated() -> onStart() -> onResume()
More information on fragment's lifecycle works can be found here: https://developer.android.com/guide/components/fragments.html
Since your fragment is not getting destroyed and recreated, your buyersProfiles
reference may hold the previous data when you return. Since the network call is not overwriting the original list, it will append the new data fetched from the network next to the existing data each time it calls it's onResponse
callback.
This may also affect use cases where you implement some kind of pull-to-refresh logic or refresh button, as the new network call will not clean the list.
One thing you could try to avoid this repetition is adding
buyersProfiles = new ArrayList<BuyerProfile>();
to the top of your onResponse()
callback.
Hope it helps.
Upvotes: 2