I am developing a small application consisting of several tabs where each tab holds just one kind of products (for example pizza products) and makes it possible to add specific product (Margherita) from this tab to an order. Each tab holds layout where there are buttons representing each product on the left side and list of items (all products) currently added to the order + calculated prices on the right side. This is the way how I currently add Tab
in TabHost
:
Bundle extras = new Bundle();
extras.putString("productType", "pizza");
tabHost.addTab(tabHost.newTabSpec("pizza").setIndicator("Pizza"), OrderFragment.class, extras);
The problem is that when I try to get arguments in a constructor of OrderFragment, it throws an exception:
E/AndroidRuntime(533): FATAL EXCEPTION: main
E/AndroidRuntime(533): java.lang.NullPointerException
The reason why I need to pass some data to the OrderFragment is that OrderFragment is GOING to be an abstract class for any kind of product (product, pasta, etc.), so it can find out, for which type of product it is and load proper data for that. I thought that the method addTab(TabSpec, Class<T>, Bundle)
creates an instance of specified class and puts extras in it but it seems like that these extras are not packed with it. (Guess it is for another purpose). I would appreciate any suggestions how to solve this. If you would do it in completely different way, I would also appreciate pointing it out.
OrderFragment:
public class OrderFragment extends Fragment implements IEditOrder{
private static final String TAG = "OrderFragment";
private Controller controller;
private ListView lst_order;
private TextView txt_order_total;
private Button btn_finishOrder;
private Button btn_cancelOrder;
private String productType;
private OrderAdapter orderAdapter;
private static final int DIALOG_EDIT_ORDER = 1;
public OrderFragment() {
Bundle extras = getArguments();
Log.d(TAG, "Extras: " + extras.toString());
this.productType = extras.getString("productType");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//setRetainInstance(true);
controller = Controller.getInstance();
controller.loadProducts(getActivity().getApplicationContext());
//FillDatabase.loadDataToDatabase(getActivity());
}
@Override
public void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_pizza, container, false);
txt_order_total = (TextView)view.findViewById(R.id.txt_order_total);
btn_finishOrder = (Button)view.findViewById(R.id.btn_finishOrder);
btn_cancelOrder = (Button)view.findViewById(R.id.btn_cancelOrder);
btn_finishOrder.setOnClickListener(finishOrder);
btn_cancelOrder.setOnClickListener(cancelOrder);
final RelativeLayout layout = (RelativeLayout) view.findViewById(R.id.rl_order_pizza);
orderAdapter = new OrderAdapter(getActivity(), controller.getOrderMap());
lst_order = (ListView) view.findViewById(R.id.lst_order);
lst_order.addHeaderView(inflater.inflate(R.layout.order_list_header, null));
lst_order.setAdapter(orderAdapter);
lst_order.setOnItemClickListener(itemClickListener);
txt_order_total.setText("Total Price: " + controller.calculateTotalPrice());
layout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
RelativeLayout.LayoutParams layoutParams;
int currentX = 20;
int currentY = 20;
for (Product product: controller.getProducts("pizza")){
layoutParams = new RelativeLayout.LayoutParams(UIConstnts.BUTTON_WIDTH, UIConstnts.BUTTON_HEIGHT);
Button tempButton = new Button(getActivity().getApplicationContext());
tempButton.setId((int)product.getId());
tempButton.setText(product.getName());
tempButton.setOnClickListener(clickListener);
layoutParams.setMargins(currentX, currentY, 0, 0);
tempButton.setLayoutParams(layoutParams);
layout.addView(tempButton);
if (layout.getWidth() < currentX + UIConstnts.MARGIN_LEFT + (2 * UIConstnts.BUTTON_WIDTH)){
currentX = 20;
currentY += UIConstnts.BUTTON_HEIGHT + UIConstnts.MARGIN_BOTTOM;
}
else{
currentX += UIConstnts.MARGIN_LEFT + UIConstnts.BUTTON_WIDTH;
}
}
layout.requestLayout();
}
});
return view;
}
private OnClickListener clickListener = new OnClickListener(){
@Override
public void onClick(View view) {
controller.addOrderItem(1, (long)view.getId());
updateQuantity();
txt_order_total.setText("Total Price: " + controller.calculateTotalPrice());
}
};
private OnItemClickListener itemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
showDialog(id, Integer.valueOf(((TextView)view.findViewById(R.id.txt_lst_quantity)).getText().toString()));
}
};
private OnClickListener finishOrder = new OnClickListener(){
@Override
public void onClick(View v) {
controller.finishOrder(getActivity());
updateQuantity();
}
};
private OnClickListener cancelOrder = new OnClickListener(){
@Override
public void onClick(View v) {
controller.resetOrder();
updateQuantity();
}
};
private void showDialog(long productId, int quantity) {
DialogFragment newFragment = EditOrderDialog.newInstance(productId, quantity, "Change Quantity");
newFragment.setTargetFragment(this, DIALOG_EDIT_ORDER);
newFragment.show(getFragmentManager(), "dialog");
}
@Override
public void updateQuantity() {
orderAdapter.setOrderList(controller.getOrderMap());
orderAdapter.notifyDataSetChanged();
txt_order_total.setText("Total Price: " + controller.calculateTotalPrice());
}
}
Picture of UI. (ListView on the right side is present on all the tabs and contains all the products in the order):
Don't ask for the arguments/extras in the constructor! They are not set at this time. They will be available later.
//If you create your Fragments yourself, create them in a static factory method:
public static Fragment newInstance(String productType){
Bundle b = new Bundle();
b.putString(ARG_PRODUCT_TYPE, productType);
Fragment f = new OrderFragment();
f.setArguments(b);
return f;
}
//Write a helper method for your arguments
public String getProductType(){
if(getArguments().containsKey(ARG_PRODUCT_TYPE)){
return getArguments().getString(ARG_PRODUCT_TYPE);
}
return null;
}
Then use the helper method after the Constructor, i.e. in onCreate().