I do have a total price in adapter OnBindViewHolder method how to send that data back to CartActivity to assign set text on the TextView in the CartActivity . should i go for Bundle to send the data to activity from the adapter or is there any other way to do it . thanks
My adapter code which extends FirestoreAdapter
public class ItemCartRecyelerAdapter extends
FirestoreAdapter<ItemCartRecyelerAdapter.ViewHolder>{
private static final String TAG = "ItemRecyelerAdapter";
private int TotalPrice = 0;
private Context context;
public interface OnItemSelectedListener {
void OnItemSelected(DocumentSnapshot item);
}
private OnItemSelectedListener mListener;
public ItemCartRecyelerAdapter(Query query, OnItemSelectedListener listener) {
super(query);
mListener = listener;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new ViewHolder(inflater.inflate(R.layout.item_cart_adapter,parent,false));
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.bind(getSnapshot(position), mListener);
Attachment attachment = getSnapshot(position).toObject(Attachment.class);
TotalPrice += attachment.getItem_price() * attachment.getItem_quantity();
Log.d(TAG, "onBindViewHolder: FinalCrossToatal: " + TotalPrice)
}
public void deleteItem(int position){
getSnapshot(position).getReference().delete();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView item_name, item_company, item_price, discount_price, discount;
ImageView item_image, subtract_image;
ElegantNumberButton quantityPicker;
int TotalPrice = 0 ;
public ViewHolder(#NonNull View itemView) {
super(itemView);
item_image = itemView.findViewById(R.id.itemImageView);
item_company = itemView.findViewById(R.id.item_company);
item_price = itemView.findViewById(R.id.item_price);
item_name = itemView.findViewById(R.id.item_name);
quantityPicker = itemView.findViewById(R.id.quantityPicker);
subtract_image = itemView.findViewById(R.id.subtract_image);
discount_price = itemView.findViewById(R.id.item_discount_price);
discount = itemView.findViewById(R.id.discount);
}
public void bind(final DocumentSnapshot snapshot, final OnItemSelectedListener listener) {
final Attachment attachment = snapshot.toObject(Attachment.class);
Resources resources = itemView.getResources();
TotalPrice += (attachment.getItem_price() * attachment.getItem_quantity());
Log.d(TAG, "bind: Totalss1 = " + TotalPrice);
item_name.setText(attachment.getItem_name());
item_company.setText(attachment.getItem_brand());
discount.setText(String.valueOf(attachment.getItem_discount()) + "%\noff");
quantityPicker.setNumber(String.valueOf(attachment.getItem_quantity()));
if (attachment.getItem_discount() != null && attachment.getItem_discount() != 0) {
subtract_image.setVisibility(View.VISIBLE);
discount_price.setVisibility(View.VISIBLE);
discount.setVisibility(View.VISIBLE);
Integer discountedPrice = attachment.getItem_price() * attachment.getItem_discount() / 100;
Integer priceDiscounted = attachment.getItem_price() - discountedPrice;
discount_price.setText(String.valueOf(priceDiscounted));
}
Log.d(TAG, "bind: Urs: " + attachment.getUrls());
for (Map.Entry<String, String> result : attachment.getUrls().entrySet()) {
String key = result.getKey();
String value = result.getValue();
Log.d(TAG, "bind: Urls+valuew" + key + value);
//Load Image
Glide.with(item_image.getContext())
.load(value)
.into(item_image);
}
quantityPicker.setRange(0, 10);
quantityPicker.setOnValueChangeListener(new ElegantNumberButton.OnValueChangeListener() {
#Override
public void onValueChange(ElegantNumberButton view, int oldValue, int newValue) {
Log.d(TAG, "onValueChange: postion " + attachment.getItem_id());
Log.d(TAG, String.format("oldValue: %d newValue: %d", oldValue, newValue));
passData(newValue, attachment.getItem_id(), oldValue);
}
private void passData(int newValue, String item_id, int oldValue) {
// Go to the details page for the selected restaurant
//sharing to seperate cart node in store
if (newValue == 0) {
FirebaseFirestore updateQ = FirebaseFirestore.getInstance();
DocumentReference CartREf = updateQ.collection("Cart")
.document(item_id);
CartREf.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: Succed to quantity");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "onFailure: Failed to change cart");
}
});
FirebaseFirestore dQ = FirebaseFirestore.getInstance();
DocumentReference QuanityRef = dQ.collection("fruits & vegetables")
.document("UyGXpk2n1A6mHsUcYjCi")
.collection("Organic Fruits")
.document(item_id);
QuanityRef.update("item_quantity", newValue).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: Success updated item_quanity in Products");
}
});
}
Log.d(TAG, "passData: new update StrARTED");
FirebaseFirestore updateQ = FirebaseFirestore.getInstance();
DocumentReference CartREf = updateQ.collection("Cart")
.document(item_id);
CartREf.update("item_quantity", newValue).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: Succed to quantity");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "onFailure: Failed to change cart");
}
});
Log.d(TAG, "passData: new update StrARTED");
FirebaseFirestore dQ = FirebaseFirestore.getInstance();
DocumentReference QuanityRef = dQ.collection("fruits & vegetables")
.document("UyGXpk2n1A6mHsUcYjCi")
.collection("Organic Fruits")
.document(item_id);
QuanityRef.update("item_quantity", newValue).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: Succed to quantity");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "onFailure: Failed to change cart");
}
});
}
});
int items_price = attachment.getItem_price() * attachment.getItem_quantity();
item_price.setText("INR " + items_price + "Rs");
//Click Listener
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (listener != null) {
listener.OnItemSelected(snapshot);
}
}
});
}
}
}
this is the method:
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.bind(getSnapshot(position), mListener);
Attachment attachment = getSnapshot(position).toObject(Attachment.class);
TotalPrice += attachment.getItem_price() * attachment.getItem_quantity();
Log.d(TAG, "onBindViewHolder: FinalCrossToatal: " + TotalPrice)
Using Interface to communicate from Recyclerviewadapter with the activity.
Create interface, and activity implements this interface.
public interface OnItemClick {
void onClick (String value);
}
When you create adapter (last parameter is this interface)
public class MainActivity extends AppCompatActivity implements OnItemClick {
recycleAdapter = new RecycleAdapter(MainActivity.this,onlineData, this);
recyclerView.setAdapter(recycleAdapter);
#Override
void onClick (String value){
//Use the data in Activity
}
// In Adapter
private OnItemClick mCallback;
RecycleAdapter(Context context,List<HashMap<String, String>> onlineData,OnItemClick listener){
this.onlineData = onlineData;
this.context = context;
this.mCallback = listener;
}
....
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.bind(getSnapshot(position), mListener);
Attachment attachment = getSnapshot(position).toObject(Attachment.class);
TotalPrice += attachment.getItem_price() * attachment.getItem_quantity();
Log.d(TAG, "onBindViewHolder: FinalCrossToatal: " + TotalPrice)
mCallback.onClick(TotalPrice);
Try Bundle to send the data in onBindViewHolder
SomeActivity activity= new SomeActivity ();
Bundle args = new Bundle();
args.putInt("totalPrice ", TotalPrice );
fragment.setArguments(args);
Related
I have CardViews in RecyclerView and each one has a delete button, when clicked it deletes data from database, remove item from ArrayList on that position and runs the animation.
When deleted it dissapears and creates a copy of it self ,Toast shows that ArrayList is empty/ without that item, but its still there I can click on it and everything, only after refreshing fragment(Changing to another fragment in bottom navigation tab or clicking on the same one) it dissapears.
This is my Adapter:
public class KitAdapter extends RecyclerView.Adapter<KitAdapter.MyViewHolder> {
Context context;
ArrayList<Kit> kitList;
OnKitClickListener clickListener;
FirebaseFirestore db;
FirebaseAuth mAuth;
FirebaseStorage FS;
String userID, saveShare;
ArrayList<String> DRList;
public KitAdapter(Context context, ArrayList<Kit> kitList, OnKitClickListener clickListener, String saveShare, ArrayList<String> DRList) {
this.context = context;
this.kitList = kitList;
this.clickListener = clickListener;
this.saveShare = saveShare;
this.DRList = DRList;
}
public ArrayList<Kit> getKitList() {
return kitList;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.kitview, parent, false);
return new MyViewHolder(v, clickListener);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
Kit kit = kitList.get(position);
db = FirebaseFirestore.getInstance();
mAuth = FirebaseAuth.getInstance();
FS = FirebaseStorage.getInstance();
this.userID = kit.getUserID();
holder.Name.setText(kit.getName());
holder.kcal.setText(kit.getKcalM() / kit.getSavedDays() + "kcal");
holder.prot.setText(kit.getProtM() / kit.getSavedDays() + "g");
holder.uh.setText(kit.getUhM() / kit.getSavedDays() + "g");
holder.mast.setText(kit.getMastM() / kit.getSavedDays() + "g");
holder.numOfDays.setText("Broj dana " + kit.getSavedDays() + "");
holder.NameS = kit.getName();
holder.kcalS = String.valueOf(kit.getKcalM());
holder.protS = String.valueOf(kit.getProtM());
holder.uhS = String.valueOf(kit.getUhM());
holder.mastS = String.valueOf(kit.getMastM());
holder.dayNums = kit.getSavedDays();
holder.DRlist = this.DRList;
holder.userID = this.userID;
if(saveShare.equals("Saved")){
if(kit.getShared().equals("No")) {
holder.saveShare.setImageResource(R.drawable.ic_upload_black_24dp);
holder.saveShare.setTag(R.drawable.ic_upload_black_24dp);
}else{
holder.saveShare.setImageResource(R.drawable.ic_file_download_done_black_24dp);
holder.saveShare.setTag(R.drawable.ic_file_download_done_black_24dp);
}
if(!userID.equals(mAuth.getCurrentUser().getUid())){
holder.saveShare.setVisibility(View.GONE);
}
}else if(saveShare.equals("Search")){
holder.saveShare.setImageResource(R.drawable.ic_file_download_black_24dp);
holder.saveShare.setTag(R.drawable.ic_file_download_black_24dp);
holder.delete.setVisibility(View.GONE);
if(DRList.contains(holder.NameS)){
holder.saveShare.setImageResource(R.drawable.ic_file_download_done_black_24dp);
holder.saveShare.setTag(R.drawable.ic_file_download_done_black_24dp);
}
}
db.collection("Users Data")
.document(this.userID)
.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
User user = task.getResult().toObject(User.class);
String userName = user.getUsername();
holder.userName.setText(userName);
}
});
FS.getReference().child(this.userID + ".jpg")
.getDownloadUrl()
.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(#NonNull Uri uri) {
Picasso.get().load(uri).into(holder.pfp);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
holder.pfp.setImageResource(R.drawable.ic_person_black_24dp);
}
});
}
#Override
public int getItemCount() {
return kitList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView Name, numOfDays, kcal, prot, uh, mast, userName;
ImageView saveShare, delete;
String NameS, kcalS, protS, uhS, mastS, userID;
int dayNums;
OnKitClickListener onKitListener;
CircleImageView pfp;
ArrayList<String> DRlist;
public MyViewHolder(#NonNull View itemView, OnKitClickListener onKitListener) {
super(itemView);
Name = itemView.findViewById(R.id.kitName);
numOfDays = itemView.findViewById(R.id.dayNum);
kcal = itemView.findViewById(R.id.kcal);
prot = itemView.findViewById(R.id.prot);
uh = itemView.findViewById(R.id.uh);
mast = itemView.findViewById(R.id.mast);
userName = itemView.findViewById(R.id.userName);
pfp = itemView.findViewById(R.id.pfp);
saveShare = itemView.findViewById(R.id.saveShare);
delete = itemView.findViewById(R.id.delete);
this.onKitListener = onKitListener;
itemView.setOnClickListener(this);
saveShare.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onKitListener.onKitAdd(getAdapterPosition(), saveShare, Name.getText().toString());
}
});
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onKitListener.onKitDelete(getAdapterPosition(), (CardView) itemView, userID);
}
});
}
#Override
public void onClick(View v) {
onKitListener.onKitClick(getAdapterPosition(), NameS, kcalS, protS, uhS, mastS, dayNums);
}
}
public interface OnKitClickListener{
void onKitClick(int position, String NameS, String kcalS, String protS, String uhS, String mastS, int dayNums);
void onKitAdd(int position, ImageView addShare, String NameS);
void onKitDelete(int position, CardView card, String userID);
}
}
This is part of code in fragment that deletes item:
#Override
public void onKitDelete(int position, CardView card, String userID) {
Handler handler = new Handler();
if(userID.equals(mAuth.getCurrentUser().getUid())) {
db.collection("Users Data")
.document(userID)
.collection("Kits")
.whereEqualTo("name", kitlist.get(position).getName())
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (!task.isSuccessful()) {
return;
}
task.getResult().getDocuments().get(0).getReference()
.delete();
}
});
}else{
db.collection("Users Data")
.document(mAuth.getCurrentUser().getUid())
.collection("Saved Kits")
.document(kitlist.get(position).getName())
.delete();
}
Toast.makeText(getContext(), kitlist.toString(), Toast.LENGTH_SHORT).show();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.zoomout);
card.startAnimation(anim);
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(kitlist.isEmpty()){
emptTxt.setVisibility(View.VISIBLE);
kitlist.remove(position);
rec.removeViewAt(position);
adapter.notifyItemRemoved(position);
}
}
},300);
}
}, 150);
}
I tried these combinations:
kitlist.remove(position);
rec.removeViewAt(position);
adapter.notifyItemRemoved(position);
//This one you can see in code above
kitlist.remove(position);
adapter.notifyDataSetChange(position)
And tried making onKitDelete default and using notfiy()/notifyAll()
public interface OnKitClickListener{
void onKitClick(int position, String NameS, String kcalS, String protS, String uhS, String mastS, int dayNums);
void onKitAdd(int position, ImageView addShare, String NameS);
default void onKitDelete(int position, CardView card, String userID){
notify();
}
}
I always get same resoult.
that's easy to update your recycler view with
android ViewModel architechtureAndroid ViewModel Docs
How can I get the first adapter position inside another adapter to set value in SQLite Database
I want to select a value from the radio button onClick of the item and save it to SQLite database
it's working fine but it takes onClick last position of the item
So I need First Adapter position in the inside adapter to save a proper value of radio button in SQLite Database
Globally Declare
int pos = 0;
Here is my first adapter code
public class CartCustomAdapter extends RecyclerView.Adapter<CartCustomAdapter.MyViewHolder> {
private List<Cart> moviesList;
public CartCustomAdapter(List<Cart> moviesList) {
this.moviesList = moviesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_cart_details, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
final List<Cart> datum = moviesList;
pos = holder.getAdapterPosition();
Log.e("POSI1", pos + "");
if (loginModel != null) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("option_name", TextUtils.join(",", Collections.singleton(datum.get(position).getShippingOption() + "")));
hashMap.put("weight", datum.get(position).getWeight() + "");
hashMap.put("zip", loginModel.getResultLogin().getZip() + "");
Log.e("Parms", hashMap + "");
showProgressDialog();
Call<CheckOutShippingInfoModel> checkOutShippingInfoModelCall = RetrofitHelper.createService(RetrofitHelper.Service.class).CheckOutShippingInfoModel(hashMap);
checkOutShippingInfoModelCall.enqueue(new Callback<CheckOutShippingInfoModel>() {
#Override
public void onResponse(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Response<CheckOutShippingInfoModel> response) {
CheckOutShippingInfoModel object = response.body();
hideProgressDialog();
if (object != null && object.getError() == false) {
Log.e("TAG", "Shipping_Response : " + new Gson().toJson(response.body()));
holder.resultCheckoutShippingInfo = object.getResultCheckoutShippingInfo();
holder.resultCheckoutShippingInfo = object.getResultCheckoutShippingInfo();
holder.shippingCustomAdapter = new ShippingCustomAdapter(holder.resultCheckoutShippingInfo,
new ResultCallback() {
#Override
public void onItemClick(int position) {
//Do, what you need...
pos = holder.getAdapterPosition();
Log.e("postion", pos + "");
}
});
holder.recyclerViewShippingInfo.setAdapter(holder.shippingCustomAdapter);
} else {
}
}
#Override
public void onFailure(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Throwable t) {
hideProgressDialog();
t.printStackTrace();
Log.e("Shipping_Response", t.getMessage() + "");
}
});
} else {
Toast.makeText(getContext(), "Please Login", Toast.LENGTH_SHORT).show();
}
}
private int grandTotal() {
int totalPrice = 0;
for (int i = 0; i < moviesList.size(); i++) {
totalPrice += moviesList.get(i).getSubtotal();
// notifyDataSetChanged();
}
return totalPrice;
}
#Override
public int getItemCount() {
return moviesList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerViewShippingInfo;
private ShippingCustomAdapter shippingCustomAdapter;
private List<ResultCheckoutShippingInfo> resultCheckoutShippingInfo;
public MyViewHolder(View view) {
super(view);
recyclerViewShippingInfo = view.findViewById(R.id.recyclerViewShippingInfo);
recyclerViewShippingInfo.setLayoutManager(new GridLayoutManager(getContext(), 1));
recyclerViewShippingInfo.setHasFixedSize(true);
recyclerViewShippingInfo.setNestedScrollingEnabled(false);
}
}
}
Here is Another Adapter Code which inside the first adapter
public class ShippingCustomAdapter extends RecyclerView.Adapter<ShippingCustomAdapter.MyViewHolder> {
private List<ResultCheckoutShippingInfo> moviesList;
private RadioGroup lastCheckedRadioGroup = null;
private int lastSelectedPosition = 0;
boolean isSelected = false;
int previousSelectedPosition = -1;
ResultCallback callback;
public ShippingCustomAdapter(List<ResultCheckoutShippingInfo> moviesList, ResultCallback callback) {
this.moviesList = moviesList;
this.callback = callback;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_shipping_info, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
final List<ResultCheckoutShippingInfo> datum = moviesList;
Log.e("POSI", pos + "--" + position + "");
holder.shipping_name.setText(datum.get(position).getType() + "");
RadioButton rb = new RadioButton(getContext());
holder.radio.addView(rb);
if (cartId.equals("Standard")) {
rb.setChecked(true);
}
if (cartId.equals("Economy")) {
rb.setChecked(true);
}
if (cartId.equals("Free")) {
rb.setChecked(true);
}
}
#Override
public int getItemCount() {
return moviesList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView shipping_name, shipping_price;
RadioGroup radio;
RadioButton radioShipping;
public MyViewHolder(View view) {
super(view);
shipping_name = view.findViewById(R.id.shipping_name);
shipping_price = view.findViewById(R.id.shipping_price);
radio = view.findViewById(R.id.price_grp);
radio.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
if (lastCheckedRadioGroup != null
&& lastCheckedRadioGroup.getCheckedRadioButtonId()
!= radioGroup.getCheckedRadioButtonId()
&& lastCheckedRadioGroup.getCheckedRadioButtonId() != -1) {
lastCheckedRadioGroup.clearCheck();
databaseHelper.updateShippingInfo(cartModel.get(pos).getId(), shipping_price.getText().toString() + "", ShippingCustomAdapter.this.moviesList.get(i).getTypeId() + "");
label_subTotal.setText("Shipping : " + shipping_value + "\n" + "Total Amount : " + mSubTotal);
}
lastCheckedRadioGroup = radioGroup;
callback.onItemClick(i);
}
});
}
}
}
Here is a database Query for updating value after radio button change
public void updateShippingInfo(String id, String shipping, String current_option) {
SQLiteDatabase db = this.getWritableDatabase();
String sql = "UPDATE " + TABLE_NAME + " SET " + " shipping" + " = " + "'" + shipping + "'" + ", current_option" + " = " + "'" + current_option + "'" + " WHERE " + "id" + " = '" + id + "'";
Log.e("QUERY", sql);
db.execSQL(sql);
}
Here is ResultCheckoutShippingInfo
public class ResultCheckoutShippingInfo {
#SerializedName("type")
#Expose
private String type;
#SerializedName("type_id")
#Expose
private String typeId;
#SerializedName("days")
#Expose
private String days;
#SerializedName("price")
#Expose
private String price;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTypeId() {
return typeId;
}
public void setTypeId(String typeId) {
this.typeId = typeId;
}
public String getDays() {
return days;
}
public void setDays(String days) {
this.days = days;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
Here I want to update database value
shipping charges = price
current_option = TypeId
using its position
You need to create: one RecyclerView.Adapter with item, that contains: photo, price, + | - buttons, delete button and radioGroup, which have dynamic radioButtons count, created using cycle by List<ResultCheckoutShippingInfo>.
public class CartCustomAdapter extends RecyclerView.Adapter<CartCustomAdapter.MyViewHolder> {
private List<Cart> moviesList;
public CartCustomAdapter(List<Cart> moviesList) {
this.moviesList = moviesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_cart_details, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
final List<Cart> datum = moviesList;
pos = holder.getAdapterPosition();
Log.e("POSI1", pos + "");
if (loginModel != null) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("option_name", TextUtils.join(",", Collections.singleton(datum.get(position).getShippingOption() + "")));
hashMap.put("weight", datum.get(position).getWeight() + "");
hashMap.put("zip", loginModel.getResultLogin().getZip() + "");
Log.e("Parms", hashMap + "");
showProgressDialog();
Call<CheckOutShippingInfoModel> checkOutShippingInfoModelCall = RetrofitHelper.createService(RetrofitHelper.Service.class).CheckOutShippingInfoModel(hashMap);
checkOutShippingInfoModelCall.enqueue(new Callback<CheckOutShippingInfoModel>() {
#Override
public void onResponse(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Response<CheckOutShippingInfoModel> response) {
CheckOutShippingInfoModel object = response.body();
hideProgressDialog();
if (object != null && object.getError() == false) {
Log.e("TAG", "Shipping_Response : " + new Gson().toJson(response.body()));
holder.resultCheckoutShippingInfo = object.getResultCheckoutShippingInfo();
//List<String> resultCheckoutShippingInfo = new ArrayList<>();
//resultCheckoutShippingInfo.add("Standard");
//resultCheckoutShippingInfo.add("Big cost");
for (ResultCheckoutShippingInfo info : holder.resultCheckoutShippingInfo){
RadioButton radioButton = new RadioButton(this);
radioButton.setText(info.name);
holder.radioShippingGroup.addView(radioButton);
//Check, if this element of radioGroup was checked in database and set checked it in radioGroup
if (info.isChecked()){
radioButton.setChecked(true);
}
}
holder.radioShippingGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
View radioButton = holder.radioShippingGroup.findViewById(checkedId);
int idx = holder.radioShippingGroup.indexOfChild(radioButton);
Log.i("TEST", "checkedId = " + Integer.toString(idx) + "; cartPosition = " + Integer.toString(position) + "; arraySize = " + Integer.toString(holder.resultCheckoutShippingInfo.size()));
databaseHelper.updateShippingInfo(
datum.get(position).getCartID,
holder.resultCheckoutShippingInfo.get(idx).getPrice() + "",
holder.resultCheckoutShippingInfo.get(idx).getTypeId() + "");
}
});
} else {
}
}
#Override
public void onFailure(#NonNull Call<CheckOutShippingInfoModel> call, #NonNull Throwable t) {
hideProgressDialog();
t.printStackTrace();
Log.e("Shipping_Response", t.getMessage() + "");
}
});
} else {
Toast.makeText(getContext(), "Please Login", Toast.LENGTH_SHORT).show();
}
}
private int grandTotal() {
int totalPrice = 0;
for (int i = 0; i < moviesList.size(); i++) {
totalPrice += moviesList.get(i).getSubtotal();
// notifyDataSetChanged();
}
return totalPrice;
}
#Override
public int getItemCount() {
return moviesList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
//RecyclerView recyclerViewShippingInfo;
//private ShippingCustomAdapter shippingCustomAdapter;
//private List<ResultCheckoutShippingInfo> resultCheckoutShippingInfo;
RadioGroup radioShippingGroup;
public MyViewHolder(View view) {
super(view);
radioShippingGroup = view.findViewById(R.id.radioShippingGroup);
//recyclerViewShippingInfo = view.findViewById(R.id.recyclerViewShippingInfo);
//recyclerViewShippingInfo.setLayoutManager(new GridLayoutManager(getContext(), 1));
//recyclerViewShippingInfo.setHasFixedSize(true);
//recyclerViewShippingInfo.setNestedScrollingEnabled(false);
}
}
}
I would suggest to use Listener pattern with few onChange callbacks. And pass it to one adapter to another. This would be cleaner solution.
My database structure
I am trying to create an activity where I can display all the logs. Just timestamp and the log message. I have tried with firebaseUI and adapter but I can't get the data to show. Best I have done was to post same last log in all positions. This is what I have so far but no success. I am new to firebase and all I need is to display the logs in a list. It can be lisView or recyclerView. If anyone can help me with code or example. Thank you.
Database structure is | "logs" node / userId / logId / fields |
public class LogActivity extends AppCompatActivity {
private static final String TAG = "LogActivity";
private static final int ACTIVITY_NUM = 3;
//widgets
private Context mContext = LogActivity.this;
private RecyclerView mLogRecycleView;
private TextView timeStamp, log;
//firebase
private DatabaseReference mLogDatabase;
private FirebaseAuth mAuth;
//adapter
private FirebaseRecyclerAdapter adapter;
//vars
private String mCurrentUserID, logID;
List<AppLogs> logsList = new ArrayList<>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log);
Log.d(TAG, "onCreate: Started");
mCurrentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
mLogRecycleView = findViewById(R.id.recyclerList);
mLogDatabase = FirebaseDatabase.getInstance().getReference().child("logs").child(mCurrentUserID);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mLogRecycleView.setHasFixedSize(true);
mLogRecycleView.setLayoutManager(linearLayoutManager);
firebaseListAdapter();
mLogRecycleView.setAdapter(adapter);
setupBottomNavigationView();
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
private void firebaseListAdapter() {
Log.d(TAG, "firebaseListAdapter: started");
Query logQuery = mLogDatabase.orderByChild("time");
FirebaseRecyclerOptions<AppLogs> options =
new FirebaseRecyclerOptions.Builder<AppLogs>()
.setQuery(logQuery, AppLogs.class).build();
adapter = new FirebaseRecyclerAdapter<AppLogs, LogViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final LogViewHolder holder, int position, #NonNull AppLogs model) {
Log.d(TAG, "onBindViewHolder: started");
//get the ID of the messages
//final String logID = getRef(position).getKey();
//Log.d(TAG, "onBindViewHolder: logID : " + logID);
Query logQuery = mLogDatabase;
logQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot singData : dataSnapshot.getChildren()) {
//AppLogs logs = dataSnapshot.getValue(AppLogs.class);
Log.d(TAG, "onChildAdded: log:==== " + singData.child("log").getValue());
//Log.d(TAG, "onChildAdded: log_ID:==== " + logs.getLog_id());
String log = singData.child("log").getValue().toString();
// String timeStamp = Long.toString(logs.getTime());
//
holder.setLog(log);
// holder.setTimeStamp(timeStamp);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#NonNull
#Override
public LogViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Log.d(TAG, "onCreateViewHolder: create users view holder: ");
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_log_list_view, parent, false);
return new LogViewHolder(view);
}
};
}
public static class LogViewHolder extends RecyclerView.ViewHolder {
View mView;
public LogViewHolder(View itemView) {
super(itemView);
this.mView = itemView;
}
public void setLog(String log) {
TextView tvLog = mView.findViewById(R.id.tvLog);
tvLog.setText(log);
}
public void setTimeStamp(String timeStamp) {
TextView tvTimeStamp = mView.findViewById(R.id.tvTimeStamp);
tvTimeStamp.setText(timeStamp);
}
}
/*
*BottomNavigationView Setup
*/
private void setupBottomNavigationView() {
Log.d(TAG, "setupBottomNavigationView: setting up BottomNavigationView");
BottomNavigationViewEx bottomNavigationViewEx = (BottomNavigationViewEx) findViewById(R.id.bottomNavViewBar);
BottomNavigationViewHelper.setupBottomNavigationView(bottomNavigationViewEx);
BottomNavigationViewHelper.enableNavigation(mContext, this, bottomNavigationViewEx);
Menu menu = bottomNavigationViewEx.getMenu();
MenuItem menuItem = menu.getItem(ACTIVITY_NUM);
menuItem.setChecked(true);
}
}
and my log model class
package com.logistics.alucard.socialnetwork.Models;
public class AppLogs {
private String log, log_id;
private long time;
public AppLogs(String log, String log_id, long time) {
this.log = log;
this.log_id = log_id;
this.time = time;
}
public AppLogs() {
}
public String getLog() {
return log;
}
public void setLog(String log) {
this.log = log;
}
public String getLog_id() {
return log_id;
}
public void setLog_id(String log_id) {
this.log_id = log_id;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
}
I manage to figure it out! Thank you for your help. Still a bit confusing how to
build queries but I'll try to get better :)
This is my solution to the firebase retrieve data:
protected void onBindViewHolder(#NonNull final LogViewHolder holder, int position, #NonNull AppLogs model) {
Log.d(TAG, "onBindViewHolder: started");
//get the ID of the messages
final String logID = getRef(position).getKey();
//Log.d(TAG, "onBindViewHolder: logID : " + logID);
Query logQuery = mLogDatabase;
logQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//AppLogs appLogs = dataSnapshot.getValue(AppLogs.class);
//Log.d(TAG, "onDataChange: logs:---------" + dataSnapshot.child(logID).child("log").getValue());
String log = dataSnapshot.child(logID).child("log").getValue().toString();
String timeStamp = dataSnapshot.child(logID).child("time").getValue().toString();
Log.d(TAG, "onDataChange: logs:--------------" + log);
holder.setLog(log);
holder.setTimeStamp(timeStamp);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
i am trying to call local API server using retrofit, in my Logcat shows that the API success called, but in my app there is nothing displayed. how i can fix this issue? and here is my code :
interface.java :
public interface Service {
#GET("vocabulary/id/*")
Call<APIResponse<List<VocabMaster>>> getVocabMaster();
}
Vocab Master.java to collect data from API :
public class VocabMaster implements Serializable {
private BigDecimal vocab_id;
private String hanzi_t;
private String hanzi_s;
private String pinyin;
private BigDecimal level_id;
private List<VocabMeaning> meaning;
public BigDecimal getVocab_id() {
return vocab_id;
}
public void setVocab_id(BigDecimal vocab_id) {
this.vocab_id = vocab_id;
}
public String getHanzi_t() {
return hanzi_t;
}
public void setHanzi_t(String hanzi_t) {
this.hanzi_t = hanzi_t;
}
public String getHanzi_s() {
return hanzi_s;
}
public void setHanzi_s(String hanzi_s) {
this.hanzi_s = hanzi_s;
}
public String getPinyin() {
return pinyin;
}
public void setPinyin(String pinyin) {
this.pinyin = pinyin;
}
public List<VocabMeaning> getMeaning() {
return meaning;
}
public void setMeaning(List<VocabMeaning> meaning) {
this.meaning = meaning;
}
public BigDecimal getLevel_id() {
return level_id;
}
public void setLevel_id(BigDecimal level_id) {
this.level_id = level_id;
}
#Override
public String toString() {
return "VocabMaster{" +
"vocab_id=" + vocab_id +
", hanzi_t='" + hanzi_t + '\'' +
", hanzi_s='" + hanzi_s + '\'' +
", pinyin='" + pinyin + '\'' +
", level_id=" + level_id +
", meaning=" + meaning +
'}';
}
}
And this is MainActivity.java :
public class MainActivity extends AppCompatActivity {
RecyclerView rvReligiVideo;
List<VocabMaster> vocabMasters = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rvReligiVideo = findViewById(R.id.rvReligi);
initReligiVideo();
loadReligiVideo();
}
private void initReligiVideo() {
LinearLayoutManager layout = new LinearLayoutManager(this);
layout.setOrientation(LinearLayoutManager.HORIZONTAL);
rvReligiVideo.setLayoutManager(layout);
VocabAdapter ar = new VocabAdapter(vocabMasters);
rvReligiVideo.setAdapter(ar);
}
//=========== Request to API ==========
private void loadReligiVideo() {
Call<APIResponse<List<VocabMaster>>> call = ServicesFactory.getService().getVocabMaster();
call.enqueue(new Callback<APIResponse<List<VocabMaster>>>() {
#Override
public void onResponse(Call<APIResponse<List<VocabMaster>>> call, Response<APIResponse<List<VocabMaster>>> response) {
if (response.isSuccessful() && response.body().isSuccessful()) {
List<VocabMaster> data = response.body().data;
if (data != null) {
vocabMasters.clear();
vocabMasters.addAll(data);
rvReligiVideo.getAdapter().notifyDataSetChanged();
}
} else {
Toast.makeText(MainActivity.this, response.errorBody().toString(), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<APIResponse<List<VocabMaster>>> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
logcat on android studio :
JSON Data Structure :
Here is my Adapter :
public class VocabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<VocabMaster> data;
public VocabAdapter(List<VocabMaster> data) {
this.data = data;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.vocabulary_model, null);
return new VH(v);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
VocabMaster vm = data.get(position);
VH vh = (VH) holder;
vh.hanziS.setText(vm.getHanzi_s());
vh.hanziT.setText(vm.getHanzi_t());
vh.pinyin.setText(vm.getPinyin());
vh.sound.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Sound", Toast.LENGTH_SHORT).show();
}
});
vh.favorite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Favorite", Toast.LENGTH_SHORT).show();
}
});
vh.share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Share", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return (data == null) ? 0 : data.size();
}
public class VH extends RecyclerView.ViewHolder {
TextView hanziS;
TextView hanziT;
TextView pinyin;
TextView desc;
ImageView sound, share, favorite;
Context context;
public VH(View itemView) {
super(itemView);
hanziS = itemView.findViewById(R.id.hanziS);
hanziT = itemView.findViewById(R.id.hanziT);
pinyin = itemView.findViewById(R.id.pinyin);
desc = itemView.findViewById(R.id.txtDesc);
sound = itemView.findViewById(R.id.imgSpeaker);
share = itemView.findViewById(R.id.imgShare);
favorite = itemView.findViewById(R.id.imgFavotite);
}
}
}
i did some changes in your code... use this
private VocabAdapter ar;
private void initReligiVideo() {
LinearLayoutManager layout = new LinearLayoutManager(this);
layout.setOrientation(LinearLayoutManager.HORIZONTAL);
rvReligiVideo.setLayoutManager(layout);
ar = new VocabAdapter(vocabMasters);
rvReligiVideo.setAdapter(ar);
}
private void loadReligiVideo() {
Call<APIResponse<List<VocabMaster>>> call = ServicesFactory.getService().getVocabMaster();
call.enqueue(new Callback<APIResponse<List<VocabMaster>>>() {
#Override
public void onResponse(Call<APIResponse<List<VocabMaster>>> call, Response<APIResponse<List<VocabMaster>>> response) {
if (response.isSuccessful() && response.body().isSuccessful()) {
List<VocabMaster> data = response.body().data;
if (data != null) {
ar.setVocoList(data);
}
} else {
Toast.makeText(MainActivity.this, response.errorBody().toString(), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<APIResponse<List<VocabMaster>>> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
}
Add this method in your adapter Class
public void setVocoList(List<VocabMaster> list){
if(list!=null)
data=list;
notifyDataSetChanged();
}
Do not change adapter's list when you have new list.
//incorrect except that the adapter is first time set to recyclerview and setVocoList is called before recyclerview.setAdater
public void setVocoList(List<VocabMaster> list){
if(list!=null)
data=list;
notifyDataSetChanged();
}
//correct
private List<VocabMaster> datas = new ArrayList()
public void setVocoList(List<VocabMaster> list){
if(list==null) return;
datas.clear();
datas.addAll(list);
notifyDataSetChanged();
}
I want to populate my recycler view so that, I can see who are the people/places nearby. I am using GeoFire to Query my database, which looks something like this.
GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(latLngCenter.latitude, latLngCenter.longitude), 0.1);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
#Override
public void onKeyEntered(String key, GeoLocation location) {
System.out.println(String.format("Key %s entered the search area at [%f,%f]", key, location.latitude, location.longitude));
Log.e("TAG", key + location.latitude + location.longitude);
}
#Override
public void onKeyExited(String key) {
System.out.println(String.format("Key %s is no longer in the search area", key));
}
#Override
public void onKeyMoved(String key, GeoLocation location) {
System.out.println(String.format("Key %s moved within the search area to [%f,%f]", key, location.latitude, location.longitude));
Log.e("TAG", key + location.latitude + location.longitude);
}
#Override
public void onGeoQueryReady() {
System.out.println("All initial data has been loaded and events have been fired!");
}
#Override
public void onGeoQueryError(DatabaseError error) {
System.err.println("There was an error with this query: " + error);
}
});
and I am using this Firebase RecyclerView
RecyclerView recycler = (RecyclerView) findViewById(R.id.RecyclerView);
recycler.setHasFixedSize(true);
recycler.setLayoutManager(new LinearLayoutManager(this));
FirebaseRecyclerAdapter<Chat, ChatHolder> mAdapter = new FirebaseRecyclerAdapter<Chat, ChatHolder>(Chat.class, R.layout.recyclerview, ChatHolder.class, mUsers) {
#Override
public void populateViewHolder(final ChatHolder chatMessageViewHolder, final Chat chatMessage, int position) {
chatMessageViewHolder.setName(chatMessage.getName());
chatMessageViewHolder.setText(chatMessage.getText());
chatMessageViewHolder.setTimestamp(chatMessage.getTimestamp());
}
};
recycler.setAdapter(mAdapter);
with these Chat Holder class and chat object class
public static class ChatHolder extends RecyclerView.ViewHolder {
View mView;
public ChatHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setName(String name) {
TextView field = (TextView) mView.findViewById(R.id.textViewName);
field.setText(name);
}
public void setText(String text) {
TextView field = (TextView) mView.findViewById(R.id.textViewMessage);
field.setText(text);
}
public void setTimestamp(String text) {
TextView field = (TextView) mView.findViewById(R.id.textViewTime);
field.setText(text);
}
}
public static class Chat {
String name;
String text;
String uid;
String timestamp;
public Chat() {
}
public Chat(String name, String uid, String message, String timestamp) {
this.name = name;
this.text = message;
this.uid = uid;
this.timestamp = timestamp;
}
public String getName() {
return name;
}
public String getUid() {
return uid;
}
public String getText() {
return text;
}
public String getTimestamp() {
return timestamp;
}
}
Currently this, adapter which is provided in FirebaseUI library, populates recyclerview so that, only one reference is used and all child events are shown in the view,
Now, I want to populate my recyclerView so that when ever a key enters it populates my recyclerview based on my key = to my reference, this how my firebase database looksmy firebase database
It'll be simpler to push all data (which is also uid) you have retrieved from geofire to a new node to store geofire results in firebase, something like
my-node //your new firebase node to store all uids retrieved from geofire
- {chatUid}: true //true is just a dummy data, you can use anything else except null and empty string.
- {chatUid}: true
- ...
and set FirebaseRecyclerAdapter ref to that node.
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("my-node");
FirebaseRecyclerAdapter fra = new FirebaseRecyclerAdapter<Boolean, MyVH>(Boolean.class, R.layout.my_layout, MyVH.class, ref) { ... }
and then, in populateViewHolder() method in your implementation of FirebaseRecyclerAdapter, you can use the String key to fetch data from main node that contains the data.
public void populateViewHolder(MyVH viewHolder, Boolean model, int position){
// Get references of child views
final TextView nameTextView = viewHolder.getItemView().findViewById(R.id.my_name_text_view_in_vh_layout);
final TextView addressTextView = viewHolder.getItemView().findViewById(R.id.my_address_text_view_in_vh_layout);
// Key in this position.
String key = getRef(position).key;
// Query the full data of the current key located in the `main-data-node`
FirebaseDatabase.getInstance().getReference("main-data-node").child(key).addValueEventListener(new ValueEventListener(){
... //Truncated onCancelled
#Override
public void onDataChange(snap: DataSnapshot){
MyDataModel model = snap.getValue(MyDataModel.class);
nameTextView = model.getName();
addressTextView = model.getAddress();
}
}
}
// The data model class
public class MyDataModel {
private String name;
private String address;
... // Truncated getter, setter, constructor
}
For any changes in geofire result, just push those results to my-node, and it will automatically informs your FirebaseRecyclerAdapter.
P.S. I'm too lazy to match my solution to your data model (sorry), so I made a simplified sample class, so if anyone stumbled upon this, they can understand it easier.
P.S.S. It's been a while since I code in java, I mainly use kotlin (and you soon should too lol), so, if there're some syntax mistakes out there, feel free to edit.
This is the Emanuelet's custom FirebaseListAdapter from which I have created by FirebaseRecyclerAdapter.
public abstract class FirebaseRecyclerAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH > implements Filterable {
private static final String LOG_TAG = "FirebaseListAdapter";
private Query mRef;
private Class<T> mModelClass;
private int mLayout;
private LayoutInflater mInflater;
protected Class<VH> mViewHolderClass;
private List<T> mModels;
private List<T> mFilteredModels;
private List<String> mKeys = new ArrayList<>();
private Map<String, T> mModelKeys;
private Map<String, T> mFilteredKeys;
private ChildEventListener mListener;
private FirebaseRecyclerAdapter.ValueFilter valueFilter;
/**
* #param mRef The Firebase location to watch for data changes. Can also be a slice of a location, using some
* combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>,
* #param mModelClass Firebase will marshall the data at a location into an instance of a class that you provide
* #param mLayout This is the mLayout used to represent a single list item. You will be responsible for populating an
* instance of the corresponding view with the data from an instance of mModelClass.
* #param activity The activity containing the ListView
*/
public FirebaseRecyclerAdapter(Query mRef, Class<T> mModelClass, int mLayout, Activity activity, Class<VH> viewHolderClass) {
this.mRef = mRef;
this.mModelClass = mModelClass;
this.mLayout = mLayout;
this.mViewHolderClass = viewHolderClass;
mInflater = activity.getLayoutInflater();
mModels = new ArrayList<>();
mModelKeys = new HashMap<>();
// Look for all child events. We will then map them to our own internal ArrayList, which backs ListView
mListener = this.mRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
T model = dataSnapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass);
mModelKeys.put(dataSnapshot.getKey(), model);
// Insert into the correct location, based on previousChildName
if (previousChildName == null) {
mModels.add(0, model);
} else {
T previousModel = mModelKeys.get(previousChildName);
int previousIndex = mModels.indexOf(previousModel);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
mModels.add(model);
mKeys.add(dataSnapshot.getKey());
} else {
mModels.add(nextIndex, model);
mKeys.add(dataSnapshot.getKey());
}
}
notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Log.d(LOG_TAG, "onChildChanged");
// One of the mModels changed. Replace it in our list and name mapping
String modelName = dataSnapshot.getKey();
T oldModel = mModelKeys.get(modelName);
T newModel = dataSnapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass);
int index = mModels.indexOf(oldModel);
mModels.set(index, newModel);
mModelKeys.put(modelName, newModel);
notifyDataSetChanged();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(LOG_TAG, "onChildRemoved");
// A model was removed from the list. Remove it from our list and the name mapping
String modelName = dataSnapshot.getKey();
T oldModel = mModelKeys.get(modelName);
mModels.remove(oldModel);
mKeys.remove(dataSnapshot.getKey());
mModelKeys.remove(modelName);
notifyDataSetChanged();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(LOG_TAG, "onChildMoved");
// A model changed position in the list. Update our list accordingly
String modelName = dataSnapshot.getKey();
T oldModel = mModelKeys.get(modelName);
T newModel = dataSnapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass);
int index = mModels.indexOf(oldModel);
mModels.remove(index);
if (previousChildName == null) {
mModels.add(0, newModel);
mKeys.add(dataSnapshot.getKey());
} else {
T previousModel = mModelKeys.get(previousChildName);
int previousIndex = mModels.indexOf(previousModel);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
mModels.add(newModel);
mKeys.add(dataSnapshot.getKey());
} else {
mModels.add(nextIndex, newModel);
mKeys.add(dataSnapshot.getKey());
}
}
notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError error) {
Log.e("FirebaseListAdapter", "Listen was cancelled, no more updates will occur");
}
});
}
public void cleanup() {
// We're being destroyed, let go of our mListener and forget about all of the mModels
mRef.removeEventListener(mListener);
mModels.clear();
mModelKeys.clear();
mKeys.clear();
}
#Override
public int getItemCount() {
return mModels.size();
}
public T getItem(int position) {
return mModels.get(position);
}
#Override
public void onBindViewHolder(VH holder, int position) {
T model = getItem(position);
populateViewHolder(holder, model, position, mKeys);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public int getItemViewType(int position) {
return mLayout;
}
public void remove(String key) {
T oldModel = mModelKeys.get(key);
mModels.remove(oldModel);
mKeys.remove(key);
mModelKeys.remove(key);
notifyDataSetChanged();
}
#Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
try {
Constructor<VH> constructor = mViewHolderClass.getConstructor(View.class);
return constructor.newInstance(view);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* Each time the data at the given Firebase location changes, this method will be called for each item that needs
* to be displayed. The arguments correspond to the mLayout and mModelClass given to the constructor of this class.
* <p/>
* Your implementation should populate the view using the data contained in the model.
*
* #param viewHolder The view to populate
* #param model The object containing the data used to populate the view
*/
protected abstract void populateViewHolder(VH viewHolder, T model, int position, List<String> mKeys);
public void addSingle(DataSnapshot snapshot) {
T model = snapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass);
mModelKeys.put(snapshot.getKey(), model);
mModels.add(model);
mKeys.add(snapshot.getKey());
notifyDataSetChanged();
}
public void update(DataSnapshot snapshot, String key) {
T oldModel = mModelKeys.get(key);
T newModel = snapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass);
int index = mModels.indexOf(oldModel);
if (index >= 0) {
mModels.set(index, newModel);
mModelKeys.put(key, newModel);
notifyDataSetChanged();
}
}
public boolean exists(String key) {
return mModelKeys.containsKey(key);
}
#Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new FirebaseRecyclerAdapter.ValueFilter();
}
return valueFilter;
}
protected abstract List<T> filters(List<T> models, CharSequence constraint);
private class ValueFilter extends Filter {
//Invoked in a worker thread to filter the data according to the constraint.
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new Filter.FilterResults();
if (mFilteredModels == null) {
mFilteredModels = new ArrayList<>(mModels); // saves the original data in mOriginalValues
mFilteredKeys = new HashMap<>(mModelKeys); // saves the original data in mOriginalValues
}
if (constraint != null && constraint.length() > 0) {
List<T> filtered = filters(mFilteredModels, constraint);
results.count = filtered.size();
results.values = filtered;
mModelKeys = filterKeys(mModels);
} else {
results.count = mFilteredModels.size();
results.values = mFilteredModels;
mModelKeys = mFilteredKeys;
}
return results;
}
//Invoked in the UI thread to publish the filtering results in the user interface.
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
Log.d(LOG_TAG, "filter for " + constraint + ", results nr: " + results.count);
mModels = (List<T>) results.values;
notifyDataSetChanged();
}
}
protected abstract Map<String, T> filterKeys(List<T> mModels);
}
Extend the PostsQueryAdapter with the FirebaseRecyclerAdapter
public class FirebasePostsQueryAdapter extends FirebaseRecyclerAdapter<Feeds, PostViewHolder> {
Activity mActivity;
/**
* #param mRef The Firebase location to watch for data changes. Can also be a slice of a location, using some
* combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>,
* #param mLayout This is the mLayout used to represent a single list item. You will be responsible for populating an
* instance of the corresponding view with the data from an instance of mModelClass.
* #param activity The activity containing the ListView
* #param viewHolderClass This is the PostsViewHolder Class which will be used to populate data.
*/
Query query;
public FirebasePostsQueryAdapter(Query mRef, int mLayout, Activity activity, Class<PostViewHolder> viewHolderClass) {
super(mRef, Feeds.class, mLayout, activity, viewHolderClass);
this.query = mRef;
this.mActivity = activity;
}
#Override
protected void populateViewHolder(final PostViewHolder viewHolder, final Feeds model, final int position, final List<String> mKeys) {
viewHolder.setPhoto(model.getThumb_url());
viewHolder.setTimestamp(DateUtils.getRelativeTimeSpanString(
(long) model.getTimestamp()).toString());
viewHolder.setAuthor(model.getUser().getFull_name(), model.getUser().getUid());
viewHolder.setIcon(model.getUser().getProfile_picture(), model.getUser().getUid());
viewHolder.setText(model.getText());
viewHolder.mPhotoView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(mActivity, SingleVideoView.class);
intent.putExtra(Constants.INTENT_VIDEO,model.getVideo_url());
intent.putExtra(Constants.KEY, mKeys.get(position));
mActivity.startActivity(intent);
}
});
ValueEventListener likeListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
viewHolder.setNumLikes(dataSnapshot.getChildrenCount());
if (dataSnapshot.hasChild(FirebaseUtil.getCurrentUserId())) {
viewHolder.setLikeStatus(PostViewHolder.LikeStatus.LIKED, mActivity);
} else {
viewHolder.setLikeStatus(PostViewHolder.LikeStatus.NOT_LIKED, mActivity);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
FirebaseUtil.getLikesRef().child(mKeys.get(position)).addValueEventListener(likeListener);
viewHolder.mLikeListener = likeListener;
}
#Override
protected List<Feeds> filters(List<Feeds> models, CharSequence constraint) {
return null;
}
#Override
protected Map<String, Feeds> filterKeys(List<Feeds> mModels) {
return null;
}
}
Where you populate the data into FirebasePostsQueryAdapter
#Override
public void onCreate() {
super.onCreate();
mFirebaseRef = FirebaseDatabase.getInstance().getReference(POSTS_STRING);
mFirebaseRef.keepSynced(true);
this.geoFire = new GeoFire(FirebaseDatabase.getInstance().getReference(GEO_POINTS));
mItemListAdapter = new FirebasePostQueryAdapter(mFirebaseRef.equalTo(GEOFIRE_CHILD), getActivity(), R.layout.list_item_items);
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
center = new GeoLocation(MainActivity.mLastLocation.getLatitude(), MainActivity.mLastLocation.getLongitude());
if (!mActiveGeoQuery) {
center = new GeoLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
startGeoQuery();
mAdapter.notifyDataSetChanged();
}
center = new GeoLocation(MainActivity.mLastLocation.getLatitude(), MainActivity.mLastLocation.getLongitude());
if (center.latitude != 0 && center.longitude != 0 && !mActiveGeoQuery) {
startGeoQuery();
} else if (mActiveGeoQuery) {
Log.d(TAG, "geoquery already active");
} else {
Log.d(TAG, "center not setted");
//I first try to set the center at the Last Known Location if retrieved
if (Double.isNaN(mCurrentLocation.getLatitude()) && mCurrentLocation.getLatitude() != 0) {
center = new GeoLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
startGeoQuery();
}
}
fragment.checkForItems();
}
private void startGeoQuery() {
query = geoFire.queryAtLocation(center, 2);
Log.d(TAG, "center: " + center.toString() + ", radius: " + 2);
query.addGeoQueryEventListener(new GeoQueryEventListener() {
#Override
public void onKeyEntered(String key, GeoLocation location) {
Log.d(TAG, "Key " + key + " entered the search area at [" + location.latitude + "," + location.longitude + "]");
DatabaseReference tempRef = mFirebaseRef.child(key);
tempRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
// I add the deal only if it doesn't exist already in the adapter
String key = snapshot.getKey();
if (!mAdapter.exists(key)) {
Log.d(TAG, "item added " + key);
mAdapter.addSingle(snapshot);
mAdapter.notifyDataSetChanged();
} else {
//...otherwise I will update the record
Log.d(TAG, "item updated: " + key);
mAdapter.update(snapshot, key);
mAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onKeyExited(String key) {
Log.d(TAG, "deal " + key + " is no longer in the search area");
mAdapter.remove(key);
fragment.isListEmpty();
}
#Override
public void onKeyMoved(String key, GeoLocation location) {
Log.d(TAG, String.format("Key " + key + " moved within the search area to [%f,%f]", location.latitude, location.longitude));
DatabaseReference tempRef = mFirebaseRef.child(key);
tempRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
// I add the deal only if it doesn't exist already in the adapter
String key = snapshot.getKey();
if (!mAdapter.exists(key)) {
Log.d(TAG, "item added " + key);
mAdapter.addSingle(snapshot);
mAdapter.notifyDataSetChanged();
} else {
//...otherwise I will update the record
Log.d(TAG, "item updated: " + key);
mAdapter.update(snapshot, key);
mAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onGeoQueryReady() {
Log.d(TAG, "All initial data has been loaded and events have been fired!");
fragment.isListEmpty();
mActiveGeoQuery = true;
}
#Override
public void onGeoQueryError(DatabaseError error) {
Log.e(TAG, "There was an error with this query: " + error);
mActiveGeoQuery = false;
}
});
fragment.bindRecyclerView();
}