Lasse
Lasse

Reputation: 601

Android ListFragment items duplication

I'm in the middel of making an app, that takes some data via a volley request, and sets the data in a ListView on a ListFragment.

My problem is that when I use my back-button to transition back to the previous activity and out of the app, (onStop), when I reopen the app from the appdrawer and go to the ListFragment, the list it shows is duplicated.

Refere pictures below:

Start of the app The list as it is shown at first The list after the app reopens from the onStop() state

The code:

The ListFragment class:

package lassebjoerklund.easyfridge;

import android.app.Activity;
import android.app.Fragment;
import android.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

/**
 * Created by lassebjorklund on 17/02/16.
 */
public class ProductsList extends ListFragment {
    ProductListListnerInteface productListListnerInteface;


    public interface ProductListListnerInteface {
        public void onProductSelected(int pos);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d(getActivity().getClass().getSimpleName(), "onCreate");
        super.onCreate(savedInstanceState);
        if(savedInstanceState == null) {
            setListAdapter(new ProductAdapter(getActivity(), BootActivity.getProductsToDisplayInlist()));
        }else{

        }
    }

    @Override
    public void onAttach(Context context) {
        Log.d(getActivity().getClass().getSimpleName(), "onAttach");
        super.onAttach(context);
        try {
            productListListnerInteface = (ProductListListnerInteface) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + "must implement ProductListListnerInteface");
        }
    }

    @Override
    public void onStart() {
        Log.d(getActivity().getClass().getSimpleName(), "onStart");
        super.onStart();
        if (getFragmentManager().findFragmentById(R.id.fragment_container_list) != null) {
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        }


    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        productListListnerInteface.onProductSelected(position);
    }




}

The Activity the binds the ListFragment with the DetailFragment (Not a part of the problem I guss)

package lassebjoerklund.easyfridge;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.KeyEvent;

/**
 * Created by lassebjorklund on 17/02/16.
 */
public class ProductViewController extends FragmentActivity implements ProductsList.ProductListListnerInteface {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.products_list_layout);
            if (findViewById(R.id.fragment_container_list) != null) {
                if (savedInstanceState != null) {
                    return;
                }
                ProductsList productsList = new ProductsList();
                productsList.setArguments(getIntent().getExtras());
                getFragmentManager().beginTransaction().add(R.id.fragment_container_list, productsList).commit();

            }

    }

    @Override
    public void onProductSelected(int pos) {
            ProductDetail productDetail = (ProductDetail) getFragmentManager().findFragmentById(R.id.details_fragment_container);

        if (productDetail != null) {

            productDetail.updateProductOnPos(pos);

        } else {
            ProductDetail newProductDetail = new ProductDetail();
            Bundle args = new Bundle();
            args.putInt("Position", pos);
            newProductDetail.setArguments(args);
            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.fragment_container_list, newProductDetail);
            fragmentTransaction.addToBackStack("ProductList");
            fragmentTransaction.commit();
        }
    }

}

The launcher activity

package lassebjoerklund.easyfridge;

import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;

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

import java.util.ArrayList;

public class BootActivity extends Activity {
    private static ArrayList<Products> productsToDisplayInlist = new ArrayList<>();
    private String TAG = BootActivity.class.getSimpleName();
    private String url = "XXXXXXXXXXXXXXXXXXXX";
    private String jsonRespons = "";
    private RequestQueue rQueue;


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        //Layout
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_boot_layout);

        //Custom Adapter for list view, for ref.
        //final ProductAdapter adapter = new ProductAdapter(this, productsToDisplayInlist);

        //RequestQueue
        rQueue = Volley.newRequestQueue(this);

        //Methode to populate Arralist


        //Intent to switch to activity
        final Intent dispalyProductsIntent = new Intent(BootActivity.this, ProductViewController.class);

        getRequest();

        final ImageButton updateViewButton = (ImageButton) findViewById(R.id.bViewProducts);
        updateViewButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                startActivity(dispalyProductsIntent);
            }

        });

    }

    public void getRequest() {
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, url, null, new Response.Listener<JSONArray>() {
            @Override
            public void onResponse(JSONArray response) {
                Log.d(TAG, response.toString());
                try {
                    for (int i = 0; i < response.length(); i++) {
                        JSONObject productToBuild = (JSONObject) response.get(i);
                        String name = productToBuild.getString("name");
                        String type = productToBuild.getString("type");
                        int id = productToBuild.optInt("id");
                        String removalDate = productToBuild.getString("removal_date");
                        String placementDate = productToBuild.getString("placement_date");
                        Products product = new Products(name, placementDate, removalDate, type);
                        productsToDisplayInlist.add(product);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                VolleyLog.d("Volly", "Error");
                error.printStackTrace();
            }
        });

        rQueue.add(jsonArrayRequest);
    }

    public void postRequest() {

    }

    public static ArrayList<Products> getProductsToDisplayInlist() {
        return productsToDisplayInlist;
    }

    @Override
    protected void onResume() {
        Log.d("onResume", "onResume");
        /*Toast toast = Toast.makeText(this, "onResume", Toast.LENGTH_LONG);
        toast.show();*/
        super.onResume();

    }

    @Override
    protected void onRestart() {
        Log.d("onRestart", "onRestart");
        /*Toast toast = Toast.makeText(this, "onRestart", Toast.LENGTH_SHORT);
        toast.show();*/
        super.onRestart();
    }

    @Override
    protected void onStop() {
        Log.d("onStop", "onStop");
       // productsToDisplayInlist.clear();
        super.onStop();
    }

    @Override
    protected void onPause() {
        Log.d("onPause", "onPause");
        super.onPause();
    }
}

I can't seem to find the problem.. Can anyone help ?

Upvotes: 0

Views: 53

Answers (2)

George Mulligan
George Mulligan

Reputation: 11903

productsToDisplayInlist is static and will not be recreated each time you go back to the BootActivity until your application itself is recreated.

When you receive the response you are only ever adding to the collection so every time the response is received you are adding duplicates.

There are many ways to fix this easiest of which is to just add productsToDisplayInlist.clear() to the beginning of onResponse() since the list is being totally repopulated anyways.

Upvotes: 2

Glenn Porter
Glenn Porter

Reputation: 536

I think the problem is that in BootActivity, you are not clearing productsToDisplayInList (productsToDisplay.clear();) before you add the products in the HTTP response to it. productsToDisplayInList is static, which means it holds its state throughout the app's lifetime. I'm not 100% sure about this, but it could be that it still contains the data whenever you leave the bottom activity in the stack (exiting the app) because the app is still running in the background.

Upvotes: 0

Related Questions