Not sure what was going on, I understand that my SizeModel object is null but I can't figure out which part of the code has an error.
Logcat
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Long com.android.ridefun.Model.SizeModel.getPrice()' on a null object reference
at com.android.ridefun.ui.fooddetail.FoodDetailFragment.calculateTotalPrice(FoodDetailFragment.java:368)
at com.android.ridefun.ui.fooddetail.FoodDetailFragment.displayInfo(FoodDetailFragment.java:356)
at com.android.ridefun.ui.fooddetail.FoodDetailFragment.lambda$onCreateView$3$FoodDetailFragment(FoodDetailFragment.java:197)
at com.android.ridefun.ui.fooddetail.-$$Lambda$FoodDetailFragment$P7ns469KVlm85g5qkSDfjwtWEhE.onChanged(Unknown Source:4)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at com.android.ridefun.ui.fooddetail.FoodDetailViewModel.setFoodModel(FoodDetailViewModel.java:41)
at com.android.ridefun.ui.fooddetail.FoodDetailFragment$1.lambda$onDataChange$0$FoodDetailFragment$1(FoodDetailFragment.java:299)
at com.android.ridefun.ui.fooddetail.-$$Lambda$FoodDetailFragment$1$kDzBYjkwuFHevzvZPfWIqjcF4o8.onComplete(Unknown Source:4)
FoodDetailFragment.java
private void displayInfo(FoodModel foodModel) {
Glide.with(getContext()).load(foodModel.getImage()).into(img_food);
food_name.setText(new StringBuilder(foodModel.getName()));
food_description.setText(new StringBuilder(foodModel.getDescription()));
food_price.setText(new StringBuilder(foodModel.getPrice().toString()));
if(foodModel.getRatingValue() != null)
ratingBar.setRating(foodModel.getRatingValue().floatValue());
((AppCompatActivity)getActivity())
.getSupportActionBar()
.setTitle(Common.selectedFood.getName());
//Size
for(SizeModel sizeModel: Common.selectedFood.getSize())
{
RadioButton radioButton = new RadioButton(getContext());
radioButton.setOnCheckedChangeListener((compoundButton, b) -> {
if(b)
Common.selectedFood.setUserSelectedSize(sizeModel);
calculateTotalPrice(); //Update price
});
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,
LinearLayout.LayoutParams.MATCH_PARENT,
1.0f);
radioButton.setLayoutParams(params);
radioButton.setText(sizeModel.getName());
radioButton.setTag(sizeModel.getPrice());
rdi_group_size.addView(radioButton);
}
if(rdi_group_size.getChildCount() > 0)
{
RadioButton radioButton = (RadioButton)rdi_group_size.getChildAt(0);
radioButton.setChecked(true); //Default first select
}
calculateTotalPrice();
}
private void calculateTotalPrice() {
double totalPrice = Double.parseDouble(Common.selectedFood.getPrice().toString()),displayPrice=0.0;
//Addon
if(Common.selectedFood.getUserSelectedAddon() != null && Common.selectedFood.getUserSelectedAddon().size() > 0)
for(AddonModel addonModel : Common.selectedFood.getUserSelectedAddon())
totalPrice+=Double.parseDouble(addonModel.getPrice().toString());
//size
totalPrice += Double.parseDouble(Common.selectedFood.getUserSelectedSize().getPrice().toString());
displayPrice = totalPrice * (Integer.parseInt(numberButton.getNumber()));
displayPrice = Math.round(displayPrice*100.0/100.0);
food_price.setText(new StringBuilder("").append(Common.formatPrice(displayPrice)).toString());
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
//Null
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
chip_group_addon.clearCheck();
chip_group_addon.removeAllViews();
for(AddonModel addonModel:Common.selectedFood.getAddon())
{
if(addonModel.getName().toLowerCase().contains(charSequence.toString().toLowerCase()))
{
Chip chip = (Chip)getLayoutInflater().inflate(R.layout.layout_addon_item,null);
chip.setText(new StringBuilder(addonModel.getName()).append("(+$")
.append(addonModel.getPrice()).append(")"));
chip.setOnCheckedChangeListener((compoundButton, b) -> {
if(b)
{
if (Common.selectedFood.getUserSelectedAddon() == null)
Common.selectedFood.setUserSelectedAddon(new ArrayList<>());
Common.selectedFood.getUserSelectedAddon().add(addonModel);
}
});
chip_group_addon.addView(chip);
}
}
}
@Override
public void afterTextChanged(Editable editable) {
}
FoodViewModel.java
public class FoodDetailFragment extends Fragment implements TextWatcher {
private FoodDetailViewModel foodDetailViewModel;
private Unbinder unbinder;
private android.app.AlertDialog waitingDialog;
private BottomSheetDialog addonBottomSheetDialog;
//View need inflate
ChipGroup chip_group_addon;
EditText edt_search;
@BindView(R.id.img_food)
ImageView img_food;
@BindView(R.id.btnCart)
CounterFab btnCart;
@BindView(R.id.btn_rating)
FloatingActionButton btn_rating;
@BindView(R.id.food_name)
TextView food_name;
@BindView(R.id.food_description)
TextView food_description;
@BindView(R.id.food_price)
TextView food_price;
@BindView(R.id.number_button)
ElegantNumberButton numberButton;
@BindView(R.id.ratingBar)
RatingBar ratingBar;
@BindView(R.id.btnShowComment)
Button btnShowComment;
@BindView(R.id.rdi_group_size)
RadioGroup rdi_group_size;
@BindView(R.id.img_add_addon)
ImageView img_add_on;
@BindView(R.id.chip_group_user_selected_addon)
ChipGroup chip_group_user_selected_addon;
@OnClick(R.id.img_add_addon)
void onAddonClick()
{
if(Common.selectedFood.getAddon() != null)
{
displayAddonList(); //show all addon options
addonBottomSheetDialog.show();
}
}
private void displayAddonList() {
if(Common.selectedFood.getAddon().size() > 0)
{
chip_group_addon.clearCheck(); //Clear check all
chip_group_addon.removeAllViews();
edt_search.addTextChangedListener(this);
//Add all view
for(AddonModel addonModel:Common.selectedFood.getAddon())
{
Chip chip = (Chip)getLayoutInflater().inflate(R.layout.layout_addon_item,null);
chip.setText(new StringBuilder(addonModel.getName()).append("(+$")
.append(addonModel.getPrice()).append(")"));
chip.setOnCheckedChangeListener((compoundButton, b) -> {
if(b)
{
if (Common.selectedFood.getUserSelectedAddon() == null)
Common.selectedFood.setUserSelectedAddon(new ArrayList<>());
Common.selectedFood.getUserSelectedAddon().add(addonModel);
}
});
chip_group_addon.addView(chip);
}
}
}
@OnClick(R.id.btn_rating)
void onRatingButtonClick()
{
showDialogRating();
}
@OnClick(R.id.btnShowComment)
void onShowCommentButtonClick() {
CommentFragment commentFragment = CommentFragment.getInstance();
commentFragment.show(getActivity().getSupportFragmentManager(),"CommentFragment");
}
private void showDialogRating() {
androidx.appcompat.app.AlertDialog.Builder builder = new androidx.appcompat.app.AlertDialog.Builder(getContext());
builder.setTitle("Rating Food");
builder.setMessage("Please fill information");
View itemView = LayoutInflater.from(getContext()).inflate(R.layout.layout_rating,null);
RatingBar ratingBar = (RatingBar)itemView.findViewById(R.id.rating_bar);
EditText edt_comment = (EditText)itemView.findViewById(R.id.edt_comment);
builder.setView(itemView);
builder.setNegativeButton("CANCEL", (dialogInterface, i) -> {
dialogInterface.dismiss();
});
builder.setPositiveButton("OK", (dialogInterface, i) -> {
CommentModel commentModel = new CommentModel();
commentModel.setName(Common.currentUser.getName());
commentModel.setUsername(Common.currentUser.getUsername());
commentModel.setComment(edt_comment.getText().toString());
commentModel.setRatingValue(ratingBar.getRating());
Map<String,Object> serverTimeStamp = new HashMap<>();
serverTimeStamp.put("timeStamp", ServerValue.TIMESTAMP);
commentModel.setCommentTimeStamp(serverTimeStamp);
foodDetailViewModel.setCommentModel(commentModel);
});
AlertDialog dialog = builder.create();
dialog.show();
}
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
foodDetailViewModel =
new ViewModelProvider(this).get(FoodDetailViewModel.class);
View root = inflater.inflate(R.layout.fragment_food_detail, container, false);
unbinder = ButterKnife.bind(this,root);
initViews();
foodDetailViewModel.getMutableLiveDataFood().observe(getViewLifecycleOwner(), foodModel -> {
displayInfo(foodModel);
});
foodDetailViewModel.getMutableLiveDataComment().observe(getViewLifecycleOwner(),commentModel -> {
submitRatingToFirebase(commentModel);
});
return root;
}
private void initViews() {
waitingDialog = new SpotsDialog.Builder().setCancelable(false).setContext(getContext()).build();
addonBottomSheetDialog = new BottomSheetDialog(getContext(),R.style.DialogStyle);
View layout_addon_display = getLayoutInflater().inflate(R.layout.layout_addon_display,null);
chip_group_addon = (ChipGroup)layout_addon_display.findViewById(R.id.chip_group_addon);
edt_search = (EditText)layout_addon_display.findViewById(R.id.edt_search);
addonBottomSheetDialog.setContentView(layout_addon_display);
addonBottomSheetDialog.setOnDismissListener(dialogInterface -> {
displayUserSelectedAddon();
calculateTotalPrice();
});
}
private void displayUserSelectedAddon() {
if(Common.selectedFood.getUserSelectedAddon() !=null &&
Common.selectedFood.getUserSelectedAddon().size() > 0)
{
chip_group_user_selected_addon.removeAllViews(); //clear all view
for(AddonModel addonModel : Common.selectedFood.getUserSelectedAddon()) //Add all available addon to list
{
Chip chip = (Chip)getLayoutInflater().inflate(R.layout.layout_chip_with_delete_icon, null);
chip.setText(new StringBuilder(addonModel.getName()).append("(+$")
.append(addonModel.getPrice()).append(")"));
chip.setClickable(false);
chip.setOnCloseIconClickListener(view -> {
//Remove when user select delete
chip_group_user_selected_addon.removeView(view);
Common.selectedFood.getUserSelectedAddon().remove(addonModel);
calculateTotalPrice();
});
chip_group_user_selected_addon.addView(chip);
}
}else if(Common.selectedFood.getUserSelectedAddon().size() == 0)
chip_group_user_selected_addon.removeAllViews();
}
private void submitRatingToFirebase(CommentModel commentModel) {
waitingDialog.show();
//Submit comment to Ref
FirebaseDatabase.getInstance()
.getReference(Common.COMMENT_REF)
.child(Common.selectedFood.getId())
.push()
.setValue(commentModel)
.addOnCompleteListener(task -> {
if(task.isSuccessful())
{
//After submit to CommentRef, update value in food
addRatingToFood(commentModel.getRatingValue());
}
});
}
private void addRatingToFood(float ratingValue) {
FirebaseDatabase.getInstance()
.getReference(Common.CATEGORY_REF)
.child(Common.categorySelected.getMenu_id()) //select category
.child("foods") // select array list 'foods' of this category
.child(Common.selectedFood.getKey()) //food item is array list
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists())
{
FoodModel foodModel = dataSnapshot.getValue(FoodModel.class);
foodModel.setKey(Common.selectedFood.getKey());
//Apply rating
if(foodModel.getRatingValue() == null)
foodModel.setRatingValue(0d);
if(foodModel.getRatingCount() == null)
foodModel.setRatingCount(0l);
double sumRating = (foodModel.getRatingValue() * foodModel.getRatingCount())+ratingValue;
long ratingCount = foodModel.getRatingCount()+1;
double result = sumRating/ratingCount;
Map<String,Object> updateData = new HashMap<>();
updateData.put("ratingValue",result);
updateData.put("ratingCount",ratingCount);
//Update data variable
foodModel.setRatingValue(result);
foodModel.setRatingCount(ratingCount);
dataSnapshot.getRef()
.updateChildren(updateData)
.addOnCompleteListener(task -> {
waitingDialog.dismiss();
if(task.isSuccessful())
{
Toast.makeText(getContext(), "Thank you", Toast.LENGTH_SHORT).show();
Common.selectedFood = foodModel;
foodDetailViewModel.setFoodModel(foodModel); //Call refresh
}
});
}
else
waitingDialog.dismiss();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
waitingDialog.dismiss();
Toast.makeText(getContext(), ""+databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private void displayInfo(FoodModel foodModel) {
Glide.with(getContext()).load(foodModel.getImage()).into(img_food);
food_name.setText(new StringBuilder(foodModel.getName()));
food_description.setText(new StringBuilder(foodModel.getDescription()));
food_price.setText(new StringBuilder(foodModel.getPrice().toString()));
if(foodModel.getRatingValue() != null)
ratingBar.setRating(foodModel.getRatingValue().floatValue());
((AppCompatActivity)getActivity())
.getSupportActionBar()
.setTitle(Common.selectedFood.getName());
//Size
for(SizeModel sizeModel: Common.selectedFood.getSize())
{
RadioButton radioButton = new RadioButton(getContext());
radioButton.setOnCheckedChangeListener((compoundButton, b) -> {
if(b)
Common.selectedFood.setUserSelectedSize(sizeModel);
calculateTotalPrice(); //Update price
});
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,
LinearLayout.LayoutParams.MATCH_PARENT,
1.0f);
radioButton.setLayoutParams(params);
radioButton.setText(sizeModel.getName());
radioButton.setTag(sizeModel.getPrice());
rdi_group_size.addView(radioButton);
}
if(rdi_group_size.getChildCount() > 0)
{
RadioButton radioButton = (RadioButton)rdi_group_size.getChildAt(0);
radioButton.setChecked(true); //Default first select
}
calculateTotalPrice();
}
private void calculateTotalPrice() {
double totalPrice = Double.parseDouble(Common.selectedFood.getPrice().toString()),displayPrice=0.0;
//Addon
if(Common.selectedFood.getUserSelectedAddon() != null && Common.selectedFood.getUserSelectedAddon().size() > 0)
for(AddonModel addonModel : Common.selectedFood.getUserSelectedAddon())
totalPrice+=Double.parseDouble(addonModel.getPrice().toString());
//size
totalPrice += Double.parseDouble(Common.selectedFood.getUserSelectedSize().getPrice().toString());
displayPrice = totalPrice * (Integer.parseInt(numberButton.getNumber()));
displayPrice = Math.round(displayPrice*100.0/100.0);
food_price.setText(new StringBuilder("").append(Common.formatPrice(displayPrice)).toString());
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
//Null
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
chip_group_addon.clearCheck();
chip_group_addon.removeAllViews();
for(AddonModel addonModel:Common.selectedFood.getAddon())
{
if(addonModel.getName().toLowerCase().contains(charSequence.toString().toLowerCase()))
{
Chip chip = (Chip)getLayoutInflater().inflate(R.layout.layout_addon_item,null);
chip.setText(new StringBuilder(addonModel.getName()).append("(+$")
.append(addonModel.getPrice()).append(")"));
chip.setOnCheckedChangeListener((compoundButton, b) -> {
if(b)
{
if (Common.selectedFood.getUserSelectedAddon() == null)
Common.selectedFood.setUserSelectedAddon(new ArrayList<>());
Common.selectedFood.getUserSelectedAddon().add(addonModel);
}
});
chip_group_addon.addView(chip);
}
}
}
@Override
public void afterTextChanged(Editable editable) {
}
SizeModel.java
public class SizeModel {
private String name;
private Long price;
public SizeModel() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}