Firebase add new child when an item on adapter is non-zero - android

Hello so I have a function in an app where you will add a data from the adapter if the quantity is non-zero and it will be saved to the firebase realtime database. What i wanna do is if the other item in adapter is non-zero it will add a child to the database but instead firebase is just replacing the item instead of adding a new child what should i do?
here is the code
public class UsualFragRViewAdapter extends RecyclerView.Adapter <UsualFragRViewAdapter.ViewHolder> {
private List<FragmentsUsualModels> items;
private Context context;
public UsualFragRViewAdapter( Context context,List<FragmentsUsualModels> items ) {
this.context = context;
this.items = items;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_usual_array, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final FragmentsUsualModels arrayitems = items.get(position);
holder.itemName.setText(arrayitems.getItemName());
holder.price.setText(String.valueOf("$ " +arrayitems.getPrice()));
holder.quantity.setNumber(arrayitems.getQuantity());
holder.card.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
holder.quantity.setOnValueChangeListener(new ElegantNumberButton.OnValueChangeListener() { //all items are located in its positions
#Override
public void onValueChange(ElegantNumberButton view, int oldValue, int newValue) { //Need to pass all non-zero items as chatview
arrayitems.setQuantity(String.valueOf(newValue));
if (newValue !=0){
String datavalue = holder.itemName.getText().toString();
String dataprice = holder.price.getText().toString();
String dataquantity = holder.quantity.getNumber().toString();
DatabaseReference data = FirebaseDatabase.getInstance().getReference("itemdata");
data.child("dataname").setValue(datavalue);
data.child("dataprice").setValue(dataprice);
data.child("dataquantity").setValue(dataquantity);
Log.d(TAG, "the new value of this data is: " +dataquantity);
Log.d(TAG, "the itemname of this position is: "+datavalue);
Log.d(TAG, "the price of this item in this position is: " +dataprice);
}
Log.d(TAG, "user changed the quantity in this position to " +arrayitems);
}
});
}
#Override
public int getItemCount() {
return items.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
CardView card;
ImageView image;
TextView itemName;
TextView price;
ElegantNumberButton quantity;
Button donebtn;
public ViewHolder(#NonNull View itemView) {
super(itemView);
card = itemView.findViewById(R.id.ucard);
image = itemView.findViewById(R.id.uimage);
itemName = itemView.findViewById(R.id.uitemName);
price = itemView.findViewById(R.id.uprice);
quantity = itemView.findViewById(R.id.uquantity);
donebtn = itemView.findViewById(R.id.udonebtn);
}
}
}

If you want to generate a new child node under a location, call push() on that DatabaseReference. So to create a new child node under itemdata:
DatabaseReference data = FirebaseDatabase.getInstance().getReference("itemdata");
DatabaseReference newData = data.push();
Now you can write the data to this new location as:
newData.child("dataname").setValue(datavalue);
newData.child("dataprice").setValue(dataprice);
newData.child("dataquantity").setValue(dataquantity);
One additional change to consider is the reducing the number of writes. Your current code does a separate setValue() call for each property. This works, but it means that any listeners will get called three times, once for each property.
While this may be what you want, it is quite common to want these writes to appear as one operation. If that is the case, you can perform a single setValue() with:
Map<String,Object> values = new HashMap<>();
values.put("dataname", datavalue);
values.put("dataprice", dataprice);
values.put("dataquantity", dataquantity);
newData.setValue(values);
The end result will be exactly the same as before, but now with a single write operation.

You should use push() to create unique id for database item
dataBase.child(/*CHILD*/).push().setValue(dataValue);

Related

Show only certain items in recycleview according to condition

I have a recycleview showing a list of audio files fetched from my audios.json file hosted on my server. i have a model class with a getter method getLanguage() to see the audio language. I would like to show only audio files of users preference in recycle view. Say for example, if user wants only english and russian i would like to show only list of russian and english. How can we achieve this? Right now the entire list is displayed.
public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.HomeDataHolder> {
int currentPlayingPosition = -1;
Context context;
ItemClickListener itemClickListener;
List<Output> wikiList;
public AudioAdapter(List<Output> wikiList, Context context) {
this.wikiList = wikiList;
this.context = context;
}
#NonNull
#Override
public HomeDataHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(R.layout.audio_row_layout,viewGroup,false);
HomeDataHolder mh = new HomeDataHolder(view);
return mh;
}
#Override
public void onBindViewHolder(#NonNull final HomeDataHolder homeDataHolder, int i) {
String desc = wikiList.get(i).getLanguage() + " • " + wikiList.get(i).getType();
homeDataHolder.tvTitle.setText(wikiList.get(i).getTitle());
homeDataHolder.tvotherinfo.setText(desc);
homeDataHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (itemClickListener != null)
itemClickListener.onClick(view,homeDataHolder.getAdapterPosition());
}
});
homeDataHolder.rippleLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (itemClickListener != null)
itemClickListener.onClick(view,homeDataHolder.getAdapterPosition());
}
});
}
#Override
public int getItemCount() {
return wikiList.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
public void setClickListener(ItemClickListener itemClickListener) { // Method for setting clicklistner interface
this.itemClickListener = itemClickListener;
}
public class HomeDataHolder extends RecyclerView.ViewHolder {
TextView tvTitle,tvotherinfo;
MaterialRippleLayout rippleLayout;
public HomeDataHolder(View v) {
super(v);
this.tvTitle = v.findViewById(R.id.title);
this.tvotherinfo = v.findViewById(R.id.audioDesc);
this.rippleLayout = v.findViewById(R.id.ripple);
}
}
}
The general idea for this should be:
you have one list with all items
you have filter rules selected by the user
You filter items from number 1, to see which ones match the constraints and store this in another list.
Then the recycler view only shows the items of the list from number 3.
This means that recycler view's getItemCount would return the size of the filtered list, not the whole list.
Instead of passing the wikiList as it is, filter it then send it:
Lets say that you filled up the wikiList, before passing it to the adapter, filter it like this:
In the activity that you initialize the adapter in:
public class YourActivity extends ............{
........
........
//your filled list
private List<Output> wikiList;
//filtered list
private List<Output> filteredList= new ArrayList<Output>();
//filters
private List<String> filters = new ArrayList<String>();
//lets say the user chooses the languages "english" and "russian" after a button click or anything (you can add as many as you want)
filters.add("english");
filters.add("russian");
//now filter the original list
for(int i = 0 ; i<wikiList.size() ; i++){
Output item = wikiList.get(i);
if(filters.contains(item.getLanguage())){
filteredList.add(item);
}
}
//now create your adapter and pass the filteredList instead of the wikiList
AudioAdapter adapter = new AudioAdapter(filteredList , this);
//set the adapter to your recyclerview........
......
.....
......
}
I use above "english" and "russian" for language. I don't know how they are set in your response, maybe you use "en" for "english" so be careful.

Getting a null object exception when using an interface

I have created a shopping cart via recyclerview. Each viewholder also has a + and - button to add or remove quantity. This functionality is done in the adapter and I have to notify the parent fragment of the updated total amount. This last bit is done via an interface. The problem is, I am getting the following error:
Process: com.ecomm.market, PID: 6630
java.lang.NullPointerException: Attempt to invoke interface method 'void com.ecomm.market.SelectionAdapter$OnUpdateCartListener.onUpdateCart(int)' on a null object reference
at com.ecomm.market.SelectionAdapter$ViewHolder$1.onClick(SelectionAdapter.java:103)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
The selected item and corresponding quantity are stored in a hashmap that I convert to an array to populate the recycler view cart. This is what the relevant part of my main fragment MenuFragment looks like:
// Using the adapter interface to add items to cart and adding up total amount
menuItemAdapter.setOnAddToCartListener(new MenuItemAdapter.OnAddToCartListener() {
#Override
public void onAddToCart(final HashMap selectionItemsHashMap) {
setupSelectionRecycler(menuView);
totalAmount = mapToArray(selectionItemsHashMap);
selectionAdapter = new SelectionAdapter(selectionItemArrayList, selectionItemsHashMap, totalAmount);
selectionRecycler.setAdapter(selectionAdapter);
cartItemsHashmap = selectionItemsHashMap;
selectionAdapter.setUpdateCartListener(new SelectionAdapter.OnUpdateCartListener() {
#Override
public void onUpdateCart(int updatedTotalAmount) {
String stringTotalAmount = Integer.toString(updatedTotalAmount);
Log.d(TAG, "received total:" +stringTotalAmount);
tvTotalAmount.setText("$"+ stringTotalAmount);
totalAmount = updatedTotalAmount;
}
});
}
});
}
And here is an excerpt from my adapter SelectionAdapter:
public class SelectionAdapter extends RecyclerView.Adapter<SelectionAdapter.ViewHolder> {
private static final String TAG = SelectionAdapter.class.getSimpleName();
private ArrayList<SelectionItem> selectionItemArrayList = new ArrayList<>();
public HashMap<String, Integer> selectionItemsHashMap = new HashMap<String, Integer>();
public int totalAmount;
private OnUpdateCartListener updateCartListener;
public interface OnUpdateCartListener {
void onUpdateCart(int totalAmount);
}
public void setUpdateCartListener(OnUpdateCartListener updateCartListener) {
this.updateCartListener = updateCartListener;
}
public SelectionAdapter(ArrayList<SelectionItem> selectionItemArrayList, HashMap<String, Integer> selectionItemsHashMap, int currentTotalAmount) {
this.selectionItemArrayList = selectionItemArrayList;
this.selectionItemsHashMap = selectionItemsHashMap;
this.totalAmount = currentTotalAmount;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.selection_card, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int position) {
viewHolder.tvSelectItem.setText(selectionItemArrayList.get(position).getSelectionName());
String quantity = Integer.toString(selectionItemArrayList.get(position).getSelectionQuantity());
viewHolder.tvDishQuantity.setText(quantity);
}
#Override
public int getItemCount() {
return selectionItemArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvSelectItem, tvDishQuantity;
ImageView addQuantity, subtractQuantity, deleteItem;
public ViewHolder(#NonNull View itemView) {
super(itemView);
tvSelectItem = itemView.findViewById(R.id.dish_selection);
tvDishQuantity = itemView.findViewById(R.id.dish_quantity);
addQuantity = itemView.findViewById(R.id.button_add);
subtractQuantity = itemView.findViewById(R.id.button_subtract);
deleteItem = itemView.findViewById(R.id.delete_item);
addQuantity.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Find the name of the menu item
int position = getAdapterPosition();
String itemName = selectionItemArrayList.get(position).getSelectionName();
// Increase quantity
int currentQuantity = selectionItemsHashMap.get(itemName);
currentQuantity += 1;
// Update the hashmap with the new quantity
selectionItemsHashMap.put(itemName,currentQuantity);
//Update total amount
for (Object name: selectionItemsHashMap.keySet()) {
String key = (String) name;
if (key.equals(selectionItemArrayList.get(position).getSelectionName())) {
int eachPrice = Integer.parseInt(selectionItemArrayList.get(position).getSelectionPrice());
totalAmount += eachPrice;
}
}
// Display the new quantity
String stringCurrentQuantity = Integer.toString(currentQuantity);
tvDishQuantity.setText(stringCurrentQuantity);
//updateCartListener.onUpdateCart(totalAmount);
}
});
}
EDIT
A couple of points:
- When the cart is initially filled, I use this same code and it works fine.
- The problem occurs once the user returns to the cart and I have to repopulate it from a bundle. Everything works fine, except when the user goes straight to the cart and attempts to alter the quantity from there.
Pass interface implementation into the constructor of Adapter as follows :
public SelectionAdapter(ArrayList<SelectionItem> selectionItemArrayList, HashMap<String, Integer> selectionItemsHashMap, int currentTotalAmount,UpdateCartListener updateCartListener ) {
this.selectionItemArrayList = selectionItemArrayList;
this.selectionItemsHashMap = selectionItemsHashMap;
this.totalAmount = currentTotalAmount;
this.updateCartListener = updateCartListener
}
This will provide an implementation of your interface on the initialization of your adapter so it will be not null when you are using it for update cart.
So you try to access the listener inside the ViewHolder which is probably the cause of the crash, what the standard way is setting the OnClickListener inside your adapter
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int position) {
viewHolder.tvSelectItem.setText(selectionItemArrayList.get(position).getSelectionName());
String quantity = Integer.toString(selectionItemArrayList.get(position).getSelectionQuantity());
viewHolder.tvDishQuantity.setText(quantity);
viewHolder.addQuantity.setOnClickListener(new View.OnClickListener() {
...
}
}
You need to instantiate your updateCartListener begfore you use it. Do updateCartListener = new WhatverClassThatImplementsYourInterafce() before you use it or make your method to override Default if you are using Java 8 using the new FunctionalInterface in java.util.Function.
I guess you forget assignment the updateCartListener in your adapter.
SelectionAdapter(selectionItemArrayList, selectionItemsHashMap, totalAmount);
cartItemsHashmap = selectionItemsHashMap;
selectionAdapter.setUpdateCartListener(new SelectionAdapter.OnUpdateCartListener() {
#Override
public void onUpdateCart(int updatedTotalAmount) {
String stringTotalAmount = Integer.toString(updatedTotalAmount);
Log.d(TAG, "received total:" +stringTotalAmount);
tvTotalAmount.setText("$"+ stringTotalAmount);
totalAmount = updatedTotalAmount;
}
});
selectionRecycler.setAdapter(selectionAdapter);

Removing element from adapter throws Index out of bound exception

I have two recycler views. The first recyclerview is basically a list of data where I can choose an item and its quantity and I am storing this chosen item data into a map. The second one is the list of the selected data. which I am generating from getting the values() from the map. The second one also has similar viewholder and I can change the quantity there also. One the quantity reaches zero I remove the item from the list and try to notifydatasetChanged().
The problem is the removing of an item from the second list is not working properly and the app crashes with error
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder
I am using a listener interface on my first Recycler so that when the quantity is changed and the item is added to the map. The adapter of the second recycler is notified of the changes. below is the code i am using to update the second recycler view.
public void updateList(){
mMap = ((UserMainActivity)getActivity()).getItemMap();
inputs.clear();
// adapter.notifyDataSetChanged();
adapter = new MyCartAdapter(inputs,getContext());
cartList.setAdapter(adapter);
for(AllItems t:mMap.values()) {
inputs.add(t);
}
adapter.notifyDataSetChanged();
}
Below is my second recycler view's adapter. Where I am changing the quantities of the selected items.
public class MyCartAdapter extends RecyclerView.Adapter<MyCartAdapter.MyCartViewHolder>{
private List<AllItems> listItems1;
private Context context;
private Typeface typeface;
public MyCartAdapter(List<AllItems> listItems1, Context context) {
this.listItems1 = listItems1;
this.context = context;
}
#NonNull
#Override
public MyCartAdapter.MyCartViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cart_items_layout, parent, false);
return new MyCartViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull final MyCartAdapter.MyCartViewHolder holder, final int position) {
final AllItems orderItem = listItems1.get(position);
holder.setProductImage(orderItem.getImageUrl(),context);
holder.name.setText(orderItem.getName());
String price = String.valueOf(orderItem.getPrice());
holder.price.setText(price);
final HashMap<String, AllItems> items = ((UserMainActivity)context).getItemMap();
holder.counter.setText(orderItem.getQuantity());
holder.add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String quantity = String.valueOf(holder.counter.getText());
int count = Integer.parseInt(quantity)+1;
holder.counter.setText(String.valueOf(count));
String url = orderItem.getImageUrl();
AllItems newitem = new AllItems(orderItem.getName(),orderItem.getComname(),url, String.valueOf(count),orderItem.getWeight,orderItem.getPrice());
((UserMainActivity)context).addItem(orderitemname,newitem);
// notifyItemChanged(position);
}
});
//counter text iitem.textview showing the quantity of the selected item . integer count returns the value of counter text below i am checking if its zero than it simply sets the value to zero and else reduce it and update the map.
holder.minus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String counterText = String.valueOf(holder.counter.getText());
int count = Integer.parseInt(counterText);
if (count==0){
holder.counter.setText("0");
}
if (count==1){
holder.counter.setText("0");
AllItems item = items.get(orderItem.getName());
if (item!=null){
String orderit = orderItem.getName();
((UserMainActivity)context).removeItem(orderit);
// here i am removing the value from the list which throws the exception
listItems1.remove(position);
notifyItemRemoved(position);
}
}
if (count>1){
String quantity = String.valueOf(count-1);
holder.counter.setText(quantity);
String orderitemname = orderItem.getName();
String url = orderItem.getImageUrl();
String weight = "100";
long weightl = Long.parseLong(weight);
AllItems newitem = new AllItems(orderItem.getName(),orderItem.getComname(),url, quantity,weight,orderItem.getPrice());
((UserMainActivity)context).addItem(orderitemname,newitem);
// listItems1.set(position, newitem);
// notifyItemChanged(position);
}
}
});
}
#Override
public int getItemCount() {
return listItems1.size();
}
public class MyCartViewHolder extends RecyclerView.ViewHolder {
public TextView name,price,count,comname;
public TextView weight;
LinearLayout add,minus;
TextView counter;
public MyCartViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.ProName);
price = (TextView) itemView.findViewById(R.id.proPrice);
weight = (TextView) itemView.findViewById(R.id.ProWeight);
counter = (TextView) itemView.findViewById(R.id.counter);
add = (LinearLayout) itemView.findViewById(R.id.addLin);
minus= (LinearLayout) itemView.findViewById(R.id.minusLin);
}
public void setProductImage(final String thumb_image, final Context ctx){
productImage = (ImageView) itemView.findViewById(R.id.ProImage);
Picasso.with(ctx).setIndicatorsEnabled(false);
Picasso.with(ctx)
.load(thumb_image)
.networkPolicy(NetworkPolicy.OFFLINE)
.placeholder(R.drawable.basket_b).into(productImage, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Picasso.with(ctx).load(thumb_image).placeholder(R.drawable.basket).into(productImage);
}
});
}
public void setComname(String name){
comname = (TextView)itemView.findViewById(R.id.proComName);
comname.setText(name);
}
}
}
This jumps out at me:
listItems1.remove(position);
notifyItemChanged(position);
The notifyItemChanged() method exists to tell the adapter that the data at the given position has changed, and that the ViewHolder should be re-bound. This is not what you're doing; you're removing an item.
Probably your app is crashing because you're removing the last item in your data set (e.g. position 10) and then telling the adapter that the item at position 10 has changed... but now the maximum position in your data set is 9.
Instead, you should use the notifyItemRemoved() method.
listItems1.remove(position);
notifyItemRemoved(position);

How to display multiple items types in RecyclerView?

I am creating an android app in java, I am using Room database.
I have three tables :
Users table( user_id and user_name)
Products table( product_id and product_name)
Orders table ( order_id , user_id and product_id )
I am using ViewModel to query information and populate it to UI.
I have one query that get from Orders table the user_id and product_id.
I have this case :
user_id number 1 have ordered 3 products.
private void setUpViewModel() {
viewModel.getUserProduct(1).observe(this,new Observer<List<OrdersTable>>() {
#Override
public void onChanged(#Nullable List<OrdersTable> order) {
mAdapter.setUserList((ArrayList<OrdersTable>) order);
}
}
);
}
this query will get product 1,2 and 3 for user No.1
I want to display the user name and product name in my recylcerView but i do not know how to display two different type of table ( User table and product table) in the recylcerView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tv_userName_xml"
android:text="user name"
android:layout_margin="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tv_prodcutName_xml"
android:layout_marginLeft="40dp"
android:text="product"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context mContext;
ArrayList<OrderTable> order_list;
ArrayList<UserTable> user_list;
ArrayList<ProductTable> product_list;
public MyAdapter(Context context) {
this.mContext = context;
}
#NonNull
#Override
public MyAdapter.MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_ts, parent, false);
MyAdapter.MyViewHolder viewHolder = new MyAdapter.MyViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull MyAdapter.MyViewHolder holder, int position) {
OrderTable orders = order_list.get(position);
UserTable user = user_list.get(position);
ProductTable productTable = product_list.get(position);
holder.tv_userName.setText(user.getUserName());
holder.tv_productName.setText(productTable.getProductName());
}
#Override
public int getItemCount() {
if (order_list == null) {
return 0;
}
return order_list.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_userName, tv_productName;
public MyViewHolder(View itemView) {
super(itemView);
tv_userName= itemView.findViewById(R.id.tv_userName_xml);
tv_productName= itemView.findViewById(R.id.tv_prodcutName_xml);
}
}
public void setTs_list(ArrayList<OrderTable> ts) {
this.order_list = ts;
notifyDataSetChanged();
}
}
You can join the data from these tables and bind that result in a custom model class called ResultModel You can get user_name and product_name from that ResultModel
user table
product table
t_order table
Join query :
select u.user_name, p.product_name from user u, product p, t_order o
where o.user_id = u.user_id and o.product_id = p.product_id
result
Create one model class ResultModel
public class ResultModel {
public String getUser_name() {
return user_name;
}
public String getProduct_name() {
return product_name;
}
private String user_name;
private String product_name;
}
Updated observer
Note: replace OrdersTable with ResultModel wherever required in your Adapter too
viewModel.getUserProduct(1).observe(this,new Observer<List<ResultModel>>() {
#Override
public void onChanged(#Nullable List<ResultModel> order) {
mAdapter.setUserList((ArrayList<ResultModel>) order);
}
}
);
}
You can create multiple recycle view inside onBindViewHolder like this
#Override
public void onBindViewHolder(ItemRowHolder itemRowHolder, int i) {
final String sectionName = dataList.get(i).getHeaderTitle();
ArrayList singleSectionItems = dataList.get(i).getAllItemsInSection();
itemRowHolder.itemTitle.setText(sectionName);
SectionListDataAdapter itemListDataAdapter = new SectionListDataAdapter(mContext, singleSectionItems);
itemRowHolder.recycler_view_list.setHasFixedSize(true);
itemRowHolder.recycler_view_list.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
itemRowHolder.recycler_view_list.setAdapter(itemListDataAdapter);
}
public class ItemRowHolder extends RecyclerView.ViewHolder {
protected TextView itemTitle;
protected RecyclerView recycler_view_list;
public ItemRowHolder(View view) {
super(view);
this.itemTitle = (TextView) view.findViewById(R.id.itemTitle);
this.recycler_view_list = (RecyclerView) view.findViewById(R.id.recycler_view_list);
}
}
See sample code here
My advice is to use different view types. Here is an article about it
First of all, you have to come up with an abstraction of a data source for your adapter. Usually we have a simple array or a list as a data source, but in your case you have not one but three types. So you can create an interface or use a collection to store all your data inside adapter, the way how you'd like to make it is up to you.
After that, you have to create different constants for each type of your models. In your example you have three models: User, Product and Order. So I'd recommend creating three constants for each of these types. These constants should be placed inside your adapter class as static fields.
private static final int USER_VIEW_TYPE = 1;
private static final int PRODUCT_VIEW_TYPE = 2;
private static final int ORDER_VIEW_TYPE = 3;
Then, you have to override method getItemViewType(int position) in your adapter. There you must tell adapter what type a particular item has. For instance, you've decided to store all your data as List<Object> (but don't do that in the production code, I'm using the Object type here just for example.). So in this case your method would look like this:
#Override public int getItemViewType(int position) {
if (data[position] instanceof User) {
return USER_VIEW_TYPE;
} else if (data[position] instanceof PRODUCT_VIEW_TYPE) {
return PRODUCT_VIEW_TYPE;
} else return ORDER_VIEW_TYPE;
}
After that you need to create different ViewHolders for your types, so you will have a UserViewHolder, a ProductViewHolder and a OrderViewHolder.
And, in order to differentiate them finally, you should use the viewType parameter in the onCreateViewHolder method. The logic is quite simple: you have to check value of this parameter and inflate different layouts depending on the result. For example:
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == USER_VIEW_TYPE) {
return new UserViewHolder(layoutInflater.inflate(R.layout.item_user_type, parent));
} else if (viewType == PRODUCT_VIEW_TYPE) {
return new ProductViewHolder(layoutInflater.inflate(R.layout.item_product_type, parent));
} else return new OrderViewHolder(layoutInflater.inflate(R.layout.item_order_type, parent));
}

Compare Old Data with New Data in Recyclerview

I am new in Android Development and working on a project where I need to call an API after every one second, in that API there is field "Amount"(dBID) which keeps on changing, so I need to update the latest Amount (dBID) in recyclerview.
In order to do so, I have called this API in a service after every interval of one second.
The data is Showing Properly no Issue.
But for Now I need to perform some action on the Old Amount and New Amount.
Action Required : I need to compare the old value (dBID) with the New Value (dBID).
If the New Value is greater then I need to change the Text Color of Amount (dBID) to BLUE.
If the New Value is smaller then I need to change the Text Color of Amount (dBID) to RED.
Tried to achieve this by storing the old data in a Variable and then Comparing it to the new Value.
Issue : This logic is working fine until there are 5 or less Items in recyclerview as soon as the sixth item is added the same logic does not work.
Help me if anyone knows how I can achieve this.
For Example you can refer an App Vertexfx : Quotes Tab.
Below is the Code which I Tried.
Adapter class of the RecyclerView:
public class QuoteAdapter extends RecyclerView.Adapter <QuoteAdapter.MyViewHolder>{
Context context;
List<QuoteData> data;
public QuoteAdapter(Context context,List<QuoteData> data)
{
this.data = data;
this.context = context;
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView time,symbol,sellmax,selllow,buymax,buylow,buy,sell,spread,lowtext,hightext;
LinearLayout layout,layoutbid,layoutask;
float currentbid,lastbid,currentask,lastask;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
time = itemView.findViewById(R.id.TVTime);
symbol = itemView.findViewById(R.id.TVSymbol);
sellmax = itemView.findViewById(R.id.TVSELLMAX);
selllow = itemView.findViewById(R.id.TVSELLLOW);
buymax = itemView.findViewById(R.id.TVBUYMAX);
buylow = itemView.findViewById(R.id.TVBUYHIGH);
buy = itemView.findViewById(R.id.TVBUY);
sell = itemView.findViewById(R.id.TVSELL);
spread = itemView.findViewById(R.id.TVSpread1);
lowtext = itemView.findViewById(R.id.low);
hightext = itemView.findViewById(R.id.high);
layout = itemView.findViewById(R.id.layout);
layoutbid = itemView.findViewById(R.id.LLBid);
layoutask = itemView.findViewById(R.id.LLAsk);
currentbid = 0;
lastbid = 0;
currentask = 0;
lastask = 0;
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.quotelist,viewGroup,false);
return new MyViewHolder(view);
}
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull final MyViewHolder myViewHolder, final int i) {
final QuoteData data1 = data.get(i);
myViewHolder.time.setText(data1.dLut);
myViewHolder.symbol.setText(data1.dSymbol);
myViewHolder.sellmax.setText(data1.dBid); //Bid
myViewHolder.selllow.setText(data1.dLow);
myViewHolder.buymax.setText(data1.dAsk); //ask
myViewHolder.buylow.setText(data1.dHigh);
myViewHolder.currentbid = Float.parseFloat((data1.dBid));
myViewHolder.currentask = Float.parseFloat((data1.dAsk));
if (myViewHolder.currentbid > myViewHolder.lastbid)
{
myViewHolder.sellmax.setTextColor(Color.BLUE);
}
if (myViewHolder.currentbid < myViewHolder.lastbid)
{
myViewHolder.sellmax.setTextColor(Color.RED);
}
myViewHolder.lastbid = myViewHolder.currentbid;
myViewHolder.lastask = myViewHolder.currentask;
}
});
}
I suggest you take a look at those classes from the Android SDK:
DiffUtil
AsyncListDiffer
ItemAnimator
DiffUtil
DiffUtil is designed to compare existing and new recycler view items and fires appropriate events. You need to pass a callback that can tell if two items are the same and if their content has changed.
AsyncListDiffer
It wraps the DiffUtil and executes it's logic asynchronously, giving better performance.
ItemAnimator
The ItemAnimator for a given RecyclerView is called by default when change events are fired on it's items. You can provide an implementation of the animateChange method to change your color accordingly.
For Future reference I have resolved the above mentioned issue using the below code.
Defined two ArrayList of String in Adapter
public class QuoteAdapter extends RecyclerView.Adapter <QuoteAdapter.MyViewHolder>{
Context context;
List<QuoteData> data;
List<String> olddatabid = new ArrayList<String>();
List<String> newdatabid = new ArrayList<String>();
List<String> olddataask = new ArrayList<String>();
List<String> newdataask = new ArrayList<String>();
class MyViewHolder extends RecyclerView.ViewHolder{
TextView time,symbol,sellmax,selllow,buymax,buylow,buy,sell,spread,lowtext,hightext;
LinearLayout layout,layoutbid,layoutask;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
time = itemView.findViewById(R.id.TVTime);
symbol = itemView.findViewById(R.id.TVSymbol);
sellmax = itemView.findViewById(R.id.TVSELLMAX);
selllow = itemView.findViewById(R.id.TVSELLLOW);
buymax = itemView.findViewById(R.id.TVBUYMAX);
buylow = itemView.findViewById(R.id.TVBUYHIGH);
buy = itemView.findViewById(R.id.TVBUY);
sell = itemView.findViewById(R.id.TVSELL);
spread = itemView.findViewById(R.id.TVSpread1);
lowtext = itemView.findViewById(R.id.low);
hightext = itemView.findViewById(R.id.high);
layout = itemView.findViewById(R.id.layout);
layoutbid = itemView.findViewById(R.id.LLBid);
layoutask = itemView.findViewById(R.id.LLAsk);
}
}
public QuoteAdapter(Context context,List<QuoteData> data)
{
this.data = data;
this.context = context;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.quotelist,viewGroup,false);
return new MyViewHolder(view);
}
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull final MyViewHolder myViewHolder, final int i) {
final QuoteData data1 = data.get(i);
myViewHolder.time.setText(data1.dLut);
myViewHolder.symbol.setText(data1.dSymbol);
myViewHolder.sellmax.setText(data1.dBid); //Bid
myViewHolder.selllow.setText(data1.dLow);
myViewHolder.buymax.setText(data1.dAsk); //ask
myViewHolder.buylow.setText(data1.dHigh);
if (newdatabid.size()< data.size())
{
newdatabid.add(data1.dBid); //Insert Value in array for the first time
}
if (olddatabid.size()< data.size())
{
olddatabid.add(data1.dBid); //Insert Value in array for the first time
}
if (newdataask.size()< data.size())
{
newdataask.add(data1.dAsk); //Insert Value in array for the first time
}
if (olddataask.size()< data.size()) //Insert Value in array for the first time
{
olddataask.add(data1.dAsk);
}
newdatabid.set(i,data1.dBid); //Store Value in array
newdataask.set(i,data1.dAsk); //Store Value in array
//Compare and perform Logic
if (Float.valueOf(newdatabid.get(i)) > Float.valueOf(olddatabid.get(i)))
{
myViewHolder.sellmax.setTextColor(Color.BLUE);
}
if (Float.valueOf(newdatabid.get(i)) < Float.valueOf(olddatabid.get(i)))
{
myViewHolder.sellmax.setTextColor(Color.RED);
}
if (Float.valueOf(newdataask.get(i)) > Float.valueOf(olddataask.get(i)))
{
myViewHolder.buymax.setTextColor(Color.BLUE);
}
if (Float.valueOf(newdataask.get(i)) < Float.valueOf(olddataask.get(i)))
{
myViewHolder.buymax.setTextColor(Color.RED);
}
olddatabid.set(i,newdatabid.get(i));
olddataask.set(i,newdataask.get(i));
}
});
}
}
#Override
public int getItemCount() {
return data.size();
}
}

Categories

Resources