stackyyflow
stackyyflow

Reputation: 763

Fragment to Fragment communication

There are two fragments (ProductDisplayFragment and PaymentFragment) in MainFragment communicating with each other side by side. MainFragment is in NavigationActivity. When an item is selected from GridView of ProductDisplayFragment, it is added into PaymentFragment ListView.

NavigationActivity act as middleman to "send" bundle product object from ProductDisplayFragment to PaymentFragment. It works perfectly fine until I switch to another Fragment of NavigationActivity, then switch back to the MainFragment (that contains both ProductDisplayFragment and PaymentFragment).

I have List<Product> productList to store the list of products added from ProductDisplayFragment in my PaymentFragment. When item is added, productList.size() is > 0 in those methods that are used to in fragment-to-fragment communication in PaymentFragment: getProduct(), updateProductInfo()

However, when I re-check productList.size() in other methods other than the two methods above that are not involved in fragment-to-fragment communication, productList.size() = 0 forever although I clicked items at ProductDisplayFragment to add items into PaymentFragment!

Why is this so? What is something that caused this weird behaviour?

ProductDisplayFragment.java

public class ProductDisplayFragment extends Fragment {

    private GridView gridView;
    private ProductGridAdapter productAdapter;
    private OnProductSelectedListener sendProduct;

    public ProductDisplayFragment() {
        // Required empty public constructor
    }

    public interface OnProductSelectedListener {
        void onProductSelected(Product product);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

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

        gridView = (GridView) rootView.findViewById(R.id.gridview);
        productAdapter = new ProductGridAdapter(getActivity(), R.layout.fragment_product_display, getProductList());
        gridView.setAdapter(productAdapter);

        return rootView;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        try {
            sendProduct = (OnProductSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(MESSAGE_ERROR_IMPLEMENTATION);
        }
    }
}

PaymentFragment.java

public class PaymentFragment extends Fragment {

    public PaymentFragment() {

    }

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

        listView = (ListView) rootView.findViewById(R.id.productList);
        paymentAdapter = new PaymentListAdapter(getActivity(), R.layout.fragment_payment, productList);
        listView.setAdapter(paymentAdapter);

        voidButton = (LinearLayout) rootView.findViewById(R.id.button_void);
        saveButton = (LinearLayout) rootView.findViewById(R.id.button_save);
        noteButton = (LinearLayout) rootView.findViewById(R.id.button_note);
        discountButton = (LinearLayout) rootView.findViewById(R.id.button_discount);
        payButton = (LinearLayout) rootView.findViewById(R.id.button_pay);
        amountSubtotal = (TextView) rootView.findViewById(R.id.amount_subtotal);
        amountDiscount = (TextView) rootView.findViewById(R.id.amount_discount);
        amountTotal = (TextView) rootView.findViewById(R.id.amount_total);

        setDefaultAmount();
        getFirstProduct();
        buttonsOnClick();

        return rootView;
    }

    /*
     * This method retrieves product from fragment and refresh the listview every time a new product is added into listview
     */
    public void getProduct(Product product) {
        updateProductInfo(product);
        updateListView();
    }

    private void updateProductInfo(Product product) {
        // Only add product if it does not exist in hashset, else increment quantity number
        if(productHash.contains(product.getBarcode())) {
            int productIndex = productList.indexOf(product);
            product.setQuantity(product.getQuantity() + 1);
            if(productIndex != -1) {
                productList.set(productIndex, product);
            }
        } else {
            product.setQuantity(1);
            productList.add(0, product);
            productHash.add(product.getBarcode());
        }
    }

    private void getFirstProduct() {
        Bundle arguments = getArguments();
        if (arguments != null) {
            Product product = (Product) arguments.getSerializable(KEY_PRODUCT);
            getProduct(product);
            if(product != null) {
                Log.d(TAG, "Received subsequent product" + product.getName());
            }
        }
    }
}

NavigationActivity.java

public class NavigationActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener,
        ProductDisplayFragment.OnProductSelectedListener {

@Override
    public void onProductSelected(Product product) {
        PaymentFragment paymentFragment = (PaymentFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_payment_list);
        if(paymentFragment != null) {
            paymentFragment.getProduct(product);
        } else {
            paymentFragment = new PaymentFragment();
            Bundle args = new Bundle();
            args.putSerializable(KEY_PRODUCT, product);
            paymentFragment.setArguments(args);

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.fragment_payment_list, paymentFragment);
            transaction.addToBackStack(null);
            transaction.commit();
            //productQueue.add(product);
            //paymentFragment.getProduct(product);
        }
    }
}

Upvotes: 1

Views: 206

Answers (1)

Alon Zilberman
Alon Zilberman

Reputation: 2155

From my experience passing heavy custom objects, especially ArrayList's of custom objects between fragments/activities often causes strange bugs. That's why I recommend you to store your List<Product> productListand all logic for managing products in a seperate singleton class and not move it across your fragments. Something like this:

public class ProductsManager{
   private static ProductsManager productManager;
   private List<Product> productList;

   private ProductsManager(){
     this.productList = new ArrayList<>();
     //Or init your productList here
   }

   public static getInstance(){
     if(productManager == null){
       productManager = new ProductsManager();
     }
   }

   public List<Product> getProductsList(){
     return productList;
   }

   public Product getProduct(){
     //Some logic
   }

   public Product updateProductInfo(Product product){
     //Some logic
   }

   //Any other method to work with your products
}

This way all your products and all logic for products managing will be in one place and you will not need to pass heavy objects across your fragments or activities. You also will be always 100% sure that all fragments work with the same data. Don't forget to create method in ProductsManager which will remove the object when you don't need it anymore.

You can use this singleton like this:

ProductsManager.getInstance().getProductsList();

Upvotes: 2

Related Questions