Reputation: 763
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
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> productList
and 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