Ordering Firebase Data in Arraylists/RecyclerView - java

I am attempting to pull data from Firebase Database into a RecyclerView and properly order them. I am successfully getting the data into the recyclerview but the ordering is wrong.
What I am getting:
Android Screenshot
Essentially it's ordering them:
Small
Enterprise
Large
Micro
Medium
My Firebase DB
It orders like this in the app MOST of the time, although one time it ordered correctly which leaves me to believe it is somewhat random depending on which task is finishing first.
I had originally looked up ordering of arraylist(How to sort ArrayList<Long> in Java in decreasing order?) and then ordering of firebase(https://firebase.google.com/docs/database/android/lists-of-data#sort_data) and wasn't sure if there is something else I'm missing?
How is the combination of the asynchronous onDataChange and the Callback decide which finishes first? It's not doing it in the order I have them in the code.
I would like them to be ordered by lowest price first, so:
Micro
Small
Medium
Large
Enterprise
Here is my code:
RegisterSubscriptionActivity.java:
public class RegisterSubscriptionActivity extends Activity {
//Firebase Database References
DatabaseReference mDatabase;
DatabaseReference mDatabaseMicro;
DatabaseReference mDatabaseSmall;
DatabaseReference mDatabaseMedium;
DatabaseReference mDatabaseLarge;
DatabaseReference mDatabaseEnterprise;
DatabaseReference mListItemRef;
ArrayList subscriptionInfo;
//Subscription (String) values
String name, number, price;
//RECYCLERVIEW ITEMS
private Context mContext;
LinearLayout mLinearLayout;
private RecyclerView mRecyclerView;
private MyAdapterSubscription mAdapter = new MyAdapterSubscription(this);
private RecyclerView.LayoutManager mLayoutManager;
//ArrayList<LinearLayout> linearLayoutList = new ArrayList<LinearLayout>();
ArrayList<Subscription> myListItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register_subscription);
myListItems = new ArrayList<Subscription>();
//CALLBACK SO YOU CAN GET THE DATA (FROM) THE ASYNC CALL AND USE IT OUTSIDE OF THE CALL, OTHERWISE IT WILL SHOW AS NULL
final DataSnapshotCallback callback = new DataSnapshotCallback() {
#Override
public void gotDataSnapshot(DataSnapshot snapshot) {
Subscription subscription = new Subscription(snapshot);
myListItems.add(subscription);
mAdapter.updateDataSet(myListItems);
Log.i("ARRAY LIST CONTENTS", myListItems.get(0).getName());
Log.i("DATA","Name: " + subscription.getName() + " Price: " + subscription.getPrice() + " Number: " + subscription.getNumber());
}
};
mDatabase = FirebaseDatabase.getInstance().getReference("Subscription");
mDatabaseMicro = mDatabase.child("Micro");
mDatabaseSmall = mDatabase.child("Small");
mDatabaseMedium = mDatabase.child("Medium");
mDatabaseLarge = mDatabase.child("Large");
mDatabaseEnterprise = mDatabase.child("Enterprise");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
callback.gotDataSnapshot(dataSnapshot); //CALLS THE CALLBACK AND SENDS THE DATASNAPSHOT TO IT
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("Cancelled",databaseError.toString());
}
}; //END of ValueEventListener
mDatabaseMicro.addListenerForSingleValueEvent(eventListener);
mDatabaseSmall.addListenerForSingleValueEvent(eventListener);
mDatabaseMedium.addListenerForSingleValueEvent(eventListener);
mDatabaseLarge.addListenerForSingleValueEvent(eventListener);
mDatabaseEnterprise.addListenerForSingleValueEvent(eventListener);
//Log.i("DATA ITEMS", "NAME: " + name + " / " + "NUMBER: " + number + " / " + "PRICE: " + price); //Will get Null because not in Callback
//Log.i("LIST OF DATA: ", myListItems.toString()); //Same
//RECYCLERVIEW STUFF
mRecyclerView = (RecyclerView) findViewById(R.id.s_recycler_view);
mContext = getApplicationContext(); // Get the application context
// Define a layout for RecyclerView
mLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(mLayoutManager);
// Set the adapter for RecyclerView
mRecyclerView.setAdapter(mAdapter);
} //END OF ONCREATE
interface DataSnapshotCallback {
void gotDataSnapshot(DataSnapshot snapshot);
}
}
Subscription.java:
public class Subscription {
String name, number;
Long price;
public Subscription(DataSnapshot dataSnapshot) {
name = dataSnapshot.child("name").getValue(String.class);
number = dataSnapshot.child("number").getValue(String.class);
price = dataSnapshot.child("price").getValue(Long.class);
}
public String getName() {
return name;
}
public String getNumber() {
return number;
}
public Long getPrice() {
return price;
}
}
MyAdapterSubscription.java:
class MyAdapterSubscription extends RecyclerView.Adapter<MyAdapterSubscription.ViewHolder> {
private ArrayList<Subscription> mDataSet = new ArrayList<>();
private Context mContext;
MyAdapterSubscription(Context context){
mContext = context;
}
static class ViewHolder extends RecyclerView.ViewHolder{
TextView nameTV, numberTV, priceTV;
ViewHolder(View v){
super(v);
nameTV = (TextView) v.findViewById(R.id.subNameTV);
numberTV = (TextView) v.findViewById(R.id.subNumberTV);
priceTV = (TextView) v.findViewById(R.id.subPriceTV);
}
}
void updateDataSet(ArrayList<Subscription> myArrayList) {
mDataSet = myArrayList;
// TODO: 12/13/2017 Sort array list by price. Lowest to highest.
//Collections.sort(mDataSet);
// TODO: 12/14/2017 Let it be clickable and link to payment
notifyDataSetChanged();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
// Create a new View
View v = LayoutInflater.from(mContext).inflate(R.layout.subscription_row_layout,parent,false);
return new ViewHolder(v);
}
//A ViewHolder object stores each of the component views inside the tag field of the Layout, so you can immediately access them without the need to look them up repeatedly.
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Subscription subscription = mDataSet.get(position);
holder.nameTV.setText(subscription.getName());
holder.numberTV.setText(subscription.getNumber());
holder.priceTV.setText(String.format(mContext.getResources().getString(R.string.subscriptionAdapterPrice), subscription.getPrice()));
}
#Override
public int getItemCount(){
return mDataSet.size();
}
}

When Firebase loads data in the order first node -> last node. Since in your structure, the order was enterprise ->...-> small, so it loads the data that way. So given if you already 5 five fixed node, you may want to reorder your structure as small -> micro -> medium -> large -> enterprise.
You can also use several Sort Data Method that firebase provided.
In your case, since you only have 5 nodes, you probably can just do a Collections.sort(arraylist, Collections.reverseOrder()) if you're reading them into an ArrayList

It is simple
Since you are using firebase datastore.
You can sort the values by these 3 methods in it.
orderByChild()
orderByKey()
orderByValue()

Related

How to prevent RecyclerView from refreshing all the datas when a newly data has been added?

I'm creating a simple chat app wherein every chatbubbles will be shown in a RecyclerView, now I noticed that every time ill enter a new data coming from Firebase RealTime Database, the old data's / or let's say the old chat bubbles will disappear and reappear once the newly added data has been displayed. I would like the old chat bubbles to not behave just like that, I would like it to remain appeared the whole time.
Here's my method to load every chatbubbles:
private void LoadChat() {
Query orderPosts = ChatRef.orderByChild("servertimestamp");
options = new FirebaseRecyclerOptions.Builder<Chat>().setQuery(orderPosts, Chat.class).build();
adapter = new FirebaseRecyclerAdapter<Chat, MyViewHolder12>(options) {
#Override
protected void onBindViewHolder(#NonNull MyViewHolder12 holder, int position, #NonNull Chat model) {
final String userpower = model.getPower();
final String pow = "Admin";
if (userpower.equals(pow)){
holder.chat_userpower.setVisibility(View.VISIBLE);
holder.chat_userpower.setText(model.getPower());
}
else{
holder.chat_userpower.setVisibility(View.GONE);
}
final String quotedc = model.getQuotedchat();
final String quotedn = model.getQuotedname();
if (quotedc == null){
holder.quotedchatbox.setVisibility(View.GONE);
holder.quotedchatboxlayout.setVisibility(View.GONE);
holder.quotedchatdescription.setVisibility(View.GONE);
}
else{
holder.quotedchatboxlayout.setVisibility(View.VISIBLE);
holder.quotedchatbox.setVisibility(View.VISIBLE);
holder.quotedchatdescription.setVisibility(View.VISIBLE);
holder.quotedchatdescription.setText("Quoted "+ model.getQuotedname() +" " + model.getQuotedchat());
}
holder.chat_usercomment.setText(model.getChat());
Picasso.get().load(model.getProfileimage()).placeholder(R.drawable.profile).into(holder.chat_userimage);
holder.chat_userdep.setText(model.getDep());
holder.chat_date.setText(model.getDate());
holder.chat_username.setText(model.getUsername());
holder.nestedchat_reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
quote = true;
quotedname = model.getUsername();
//CommentKey = getRef(holder.getAdapterPosition()).getKey();
quoting.setVisibility(View.VISIBLE);
quotedchat = model.getChat();
quoting.setText("Quoting "+ quotedname + ": " + model.getChat());
quoting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
quote = false;
quoting.setVisibility(View.GONE);
}
});
}
});
}
#NonNull
#Override
public MyViewHolder12 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.allchatlayout, parent, false);
return new MyViewHolder12(view);
}
};
adapter.startListening();
allchatlist.setAdapter(adapter);
}
here's my layoutmanager:
LinearLayoutManager lm = new LinearLayoutManager(this);
lm.setReverseLayout(false);
lm.setStackFromEnd(false);
allchatlist.setNestedScrollingEnabled(false);
allchatlist.setLayoutManager(lm);
here's my code calling the method:
ChatRef = FirebaseDatabase.getInstance().getReference().child("Forums").child(ChatRoomNameKey).child("Forum ChatRoom");
ChatRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()){
LoadChat();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
To achieve that you will have to use RecyclerView DiffUtill class, more info here:
https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil
In a nutshell you have to create a diff util class:
class CustomItemDiffUtils(
private val oldList: List<CustomItem>,
private val newList: List<CustomItem>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].data == newList[newItemPosition].data
}
}
And use this diff class in your adapter fro example with a method which can be called from the view:
fun updateList(newList: List<CustomItem>) {
val diffResult = DiffUtil.calculateDiff(CustomItemDiffUtils(oldList, newList))
oldList = newList
diffResult.dispatchUpdatesTo(this)
}
Hope this helps.
I fixed the problem by removing the line:
Query orderPosts = ChatRef.orderByChild("servertimestamp");
options = new FirebaseRecyclerOptions.Builder<Chat>().setQuery(orderPosts, Chat.class).build();
Removing that 2 lines of code from that method and putting it somewhere else inside the Activity fixed the blinking problem of my app when a new data has been added.

Second activity can't read getExtras from intent

I'm trying to get the values from a recyclerView item (Firestore as database) in a new activity by using intents if I click on it. Don't know if that is the best way, but I got so far.
In my second activity I only get Null in the textViews I want to populate.
I've tried to test it with Toasts. You will see there is two Toast messages. The first one in the mainActivity (UltraLiquors) show the data I want to pull correctly (the ID, product and price), but the second one in the details activity only shows "null", so I assume there is a problem with my getExtras in my detail activity. I just don't know where to look anymore.
Please be so kind and help, I really have been struggling with this a few days.
Here is my mainActivity (UltraLiquors.class)
public class UltraLiquors extends AppCompatActivity {
private FirebaseFirestore ultra_liquor_db = FirebaseFirestore.getInstance();
private CollectionReference promo_oneRef = ultra_liquor_db.collection("ultra_liquors");
private static final int ACTIVITY_NUM = 2;
private UltraLiquorsRecyclerAdapter ultra_liquors_adapter;
private static final String TAG = "Ultra Liquors";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ultra_liquors);
setUpPromoOneRecyclerView();
//setupBottomNavigationView();
setTitle("Ultra Liquors");
Context context;
}
private void setUpPromoOneRecyclerView() {
Query query = promo_oneRef.whereEqualTo("promo_number", "1").orderBy("department");
FirestoreRecyclerOptions<Ultra_liquors> options = new FirestoreRecyclerOptions.Builder<Ultra_liquors>()
.setQuery(query, Ultra_liquors.class)
.build();
ultra_liquors_adapter = new UltraLiquorsRecyclerAdapter(options);
RecyclerView promo_one_recyclerView = findViewById(R.id.recycler_view_ultra_liquors);
//recyclerView.setHasFixedSize(true);
promo_one_recyclerView.setLayoutManager(new LinearLayoutManager(this));
promo_one_recyclerView.setAdapter(ultra_liquors_adapter);
ultra_liquors_adapter.setOnItemClickListener(new UltraLiquorsRecyclerAdapter.OnItemClickListener() {
#Override
public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
Ultra_liquors note = documentSnapshot.toObject(Ultra_liquors.class);
String id = documentSnapshot.getId();
String product = (String) documentSnapshot.get("product");
String price = (String) documentSnapshot.get("price");
String path = documentSnapshot.getReference().getPath();
Toast.makeText(UltraLiquors.this,
"Position: " + position + " ID: " + product + price, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(UltraLiquors.this, ViewProduct.class);
intent.putExtra("Product", product);
intent.putExtra("Price", price);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
ultra_liquors_adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
ultra_liquors_adapter.stopListening();
}
}
And here is the detailActivity (ViewProduct) where I want to pull the data from the intent:
public class ViewProduct extends AppCompatActivity {
private String edit_product_ID;
//private String edit_product_Product;
private String edit_product_Price;
private TextView productView, priceView;
private TextView mSave, mDelete;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_product);
Intent intent = getIntent();
String product;
String price;
product = String.valueOf(getIntent().getExtras().get("product"));
price = String.valueOf(getIntent().getExtras().get("price"));
Toast.makeText(this, "The Product ID: " + edit_product_ID +
" Product Name " + product + " Product Price " + price, Toast.LENGTH_LONG).show();
TextView productView = findViewById(R.id.product);
productView.setText(product);
TextView priceView = findViewById(R.id.price);
priceView.setText(price);
mSave = (TextView) findViewById(R.id.save);
mDelete = (TextView) findViewById(R.id.delete);
}}
I am not the best yet with Java or Android, so please be patient.
You're using:
intent.putExtra("Product", product);
intent.putExtra("Price", price);
But then you're trying to get them with:
product = String.valueOf(getIntent().getExtras().get("product"));
price = String.valueOf(getIntent().getExtras().get("price"));
See how these values are different ?
You need to use the same casing, as it's case sensitive, so use something like:
product = String.valueOf(getIntent().getExtras().get("Product"));
price = String.valueOf(getIntent().getExtras().get("Price"));

ArrayList add() sometimes does not add element obtained from Firebase to ArrayList

So, I am trying to create a listView that shows the rooms that have an appointment set. The problem is that such rooms and date of appointment are not added into the ArrayLists in some cases. I have to constantly open and close the activity to get a situation where they are indeed added and shown in the ListView.
// Global variables
ArrayList<Room> rooms = new ArrayList<>();
ArrayList<String> dates = new ArrayList<>();
private DatabaseReference appointmentsRef;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
// Other stuff
appointmentsRef= FirebaseDatabase.getInstance().getReference();
appointmentsRef.child("appointment").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(final DataSnapshot snapshot : dataSnapshot.getChildren()){
final Appointment cita = snapshot.getValue(Appointment.class);
FirebaseDatabase.getInstance().getReference().child("room").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dS) {
for(DataSnapshot ss : dS.getChildren()){
Room room = ss.getValue(Room.class);
if(room.getId().equals(cita.getRoomID())){
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + " rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e("Canceled","Cancelled appointment loop");
}
});
}
Log.e("Rooms", rooms.toString());
Log.e("Dates", dates.toString());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e("Canceled","Cancelled room loop");
}
}
The code always goes through the if conditions where the output is shown as following but the ArrayLists are shown on the logfile as empty.
E/Rooms: []
E/Dates: []
E/Pass: Room 1b845370-39d0-4e35-9e15-b9eaf6d556b5 in appointment 1803b7a8-7cfc-4c43-8bad-573868d174f5 rented room 1b845370-39d0-4e35-9e15-b9eaf6d556b5
E/Pass: Room 6640904b-edc6-4b1e-b636-a68cb72241ad in appointment a206e8f5-76e3-40cc-91de-e64a976691e9 rented room 6640904b-edc6-4b1e-b636-a68cb72241ad
Update: I moved the Log.e that printed the ArrayLists after the if statement as answered. In fact, the ArrayLists were never empty, so why is it that such Rooms and dates are not shown in the List view from the activity?
// Inside onCreate before appointmentsRef
ListView lv = findViewById(R.id.listViewHistory);
// after appointmentsRef
HistoryAdapter adapter = new HistoryAdapter(this, R.layout.history_adapter_view,rooms,dates);
lv.setAdapter(adapter);
HistoryAdapter:
public class HistoryAdapter extends ArrayAdapter<Room> {
private static final String TAG = "HistoryAdapter";
private Context mContext;
private int mResource;
//ViewHolder object
ViewHolder holder;
ArrayList<String> appointments;
private static class ViewHolder {
TextView title;
TextView location;
TextView price;
TextView date;
ImageView image;
}
public HistoryAdapter(Context context, int resource, ArrayList<Room> objects,ArrayList<String> dates) {
super(context, resource, objects);
mContext = context;
mResource = resource;
this.appointments = dates;
}
#NonNull
public View getView(int position, View convertView, ViewGroup parent) {
//sets up the image loader library
setupImageLoader();
//get the Appointment information
// String currentUser = ""+ FirebaseAuth.getInstance().getCurrentUser().getUid();
//String day = "placeholder";
String day = appointments.get(position);
String title = getItem(position).getTitle();
String location = getItem(position).getLocation();
String price = "$"+getItem(position).getPrice();
String imgUrl = getItem(position).getPhoto();
Log.e("Position","PosiciĆ³n : "+ position);
//create the view result for showing the animation
final View result;
if(convertView == null){
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
holder= new HistoryAdapter.ViewHolder();
holder.title = convertView.findViewById(R.id.tvTitle);
holder.location = convertView.findViewById(R.id.tvLocation);
holder.price = convertView.findViewById(R.id.tvPrice);
holder.date = convertView.findViewById(R.id.tvDate);
holder.image = convertView.findViewById(R.id.image);
result = convertView;
convertView.setTag(holder);
}
else{
holder = (HistoryAdapter.ViewHolder) convertView.getTag();
result = convertView;
}
// Animation animation = AnimationUtils.loadAnimation(mContext,
// (position > lastPosition) ? R.anim.load_down_anim : R.anim.load_up_anim);
//result.startAnimation(animation);
holder.title.setText(title);
holder.location.setText(location);
holder.price.setText(price);
holder.date.setText(day);
//create the imageloader object
ImageLoader imageLoader = ImageLoader.getInstance();
;
int defaultImage = mContext.getResources().getIdentifier("#drawable/logo_size",null,mContext.getPackageName());
//create display options
DisplayImageOptions options = new DisplayImageOptions.Builder().cacheInMemory(true)
.cacheOnDisc(true).resetViewBeforeLoading(true)
.showImageForEmptyUri(defaultImage)
.showImageOnFail(defaultImage)
.showImageOnLoading(defaultImage).build();
//download and display image from url
imageLoader.displayImage(imgUrl, holder.image, options);
return convertView;
}
/**
* Required for setting up the Universal Image loader Library
*/
private void setupImageLoader(){
// UNIVERSAL IMAGE LOADER SETUP
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheOnDisc(true).cacheInMemory(true)
.imageScaleType(ImageScaleType.EXACTLY)
.displayer(new FadeInBitmapDisplayer(300)).build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
mContext)
.defaultDisplayImageOptions(defaultOptions)
.memoryCache(new WeakMemoryCache())
.discCacheSize(100 * 1024 * 1024).build();
ImageLoader.getInstance().init(config);
// END - UNIVERSAL IMAGE LOADER SETUP
}
}
Your issue is that your if statement is running inside the onDataChanged method, which is asynchronous, and will be run in a different thread.
In other words, you will first addValueEventListener, and the code will then immediately move onto the next line of code, where you log the lists.
If you move the logs to just after the if statement inside your inner onDataChanged(), you will see it is working as expected.
You are adding ValueEventListener on child "room" and then calling Log.e("Rooms", rooms.toString()); and Log.e("Dates", dates.toString()); , But the below function will be called in future when the data is changed. That's why rooms and dates are empty.
#Override
public void onDataChange(#NonNull DataSnapshot dS) {
for(DataSnapshot ss : dS.getChildren()){
Room room = ss.getValue(Room.class);
if(room.getId().equals(cita.getRoomID())){
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + " rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
}
}
Log.e("Rooms", rooms.toString());
Log.e("Dates", dates.toString());
}
Modify the function like below and then see the output:
#Override
public void onDataChange(#NonNull DataSnapshot dS) {
for(DataSnapshot ss : dS.getChildren()){
Room room = ss.getValue(Room.class);
if(room.getId().equals(cita.getRoomID())){
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + " rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
}
}
Log.e("Rooms", rooms.toString());
Log.e("Dates", dates.toString());
}
The ArrayLists are updated asynchronously. Even though the code logging their contents is below the code that updates them, it is actually run first, while they are still empty. If you need to work with them after they are updated, place your code in the callback like this:
for(DataSnapshot ss : dS.getChildren()){
Room room = ss.getValue(Room.class);
if (room.getId().equals(cita.getRoomID())) {
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + "
rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
}
// at this point rooms and dates have been populated. place code that needs
// to work with these populated ArrayLists here.
}

Array Adapter is not updating in onDataChange() method

This is my ArrayAdapter:
public class SackViewAdapter extends ArrayAdapter<PostInfo> {
private ArrayList<PostInfo> postInfo;
private Context context;
private LayoutInflater inflater;
public SackViewAdapter(#NonNull Context context, int resource,ArrayList<PostInfo> postInfo) {
super (context, resource);
this.context = context;
this.postInfo = postInfo;
inflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
Log.e ("Size", String.valueOf (postInfo.size ()));
return postInfo.size ();
}
#Nullable
#Override
public PostInfo getItem(int i) {
return postInfo.get (i);
}
#NonNull
#Override
public View getView(int i, View view, #NonNull ViewGroup parent) {
view = inflater.inflate (R.layout.card_sack_view, parent,false);
SelectableRoundedImageView imageView = view.findViewById (R.id.image_view);
TextView name = view.findViewById (R.id.nameCards);
TextView username = view.findViewById (R.id.usernameCards);
imageView.setDrawingCacheEnabled (true);
name.setText (postInfo.get (i).name);
username.setText (postInfo.get (i).username);
try{
Glide.with (context).load (postInfo.get (i).Url).into (imageView);
}catch (Exception e){
Toast.makeText (context, e.getMessage (), Toast.LENGTH_SHORT).show ();
}
Log.e ("i", String.valueOf (i));
return view;
}
}
This is my Main Activity:
public class WallActivity extends AppCompatActivity {
FloatingActionButton newFloatingButton;
SackViewAdapter baseAdapter;
ArrayList<PostInfo> postInfos;
DatabaseReference reference = FirebaseDatabase.getInstance ().getReference ();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_wall);
postInfos = new ArrayList<PostInfo> ();
String isDirectly = getIntent ().getStringExtra ("directly");
if(isDirectly.equals ("yes")){
AuthAsyncTask authAsyncTask = new AuthAsyncTask (WallActivity.this);
authAsyncTask.execute ();
}
getData ();
CardStackView cardStackView = findViewById(R.id.cardView);
newFloatingButton = findViewById(R.id.newFloatingButton);
newFloatingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(WallActivity.this, NewItemActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_up, R.anim.slide_down);
}
});
cardStackView.setCardEventListener(new CardStackView.CardEventListener() {
#Override
public void onCardDragging(float percentX, float percentY) {
}
#Override
public void onCardSwiped(SwipeDirection direction) {
}
#Override
public void onCardReversed() {
}
#Override
public void onCardMovedToOrigin() {
}
#Override
public void onCardClicked(int index) {
Toast.makeText(WallActivity.this, "Clicked", Toast.LENGTH_SHORT).show();
}
});
baseAdapter = new SackViewAdapter (WallActivity.this,android.R.layout.simple_list_item_1, postInfos);
cardStackView.setAdapter(baseAdapter);
}
public void getData(){
reference.addValueEventListener (new ValueEventListener () {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
DataSnapshot posts = dataSnapshot.child ("Posts");
for (DataSnapshot time: posts.getChildren ()){
DataSnapshot url = time.child ("Url");
DataSnapshot name = time.child ("Name");
DataSnapshot username = time.child ("Username");
DataSnapshot date = time.child ("Date");
PostInfo postInfo = new PostInfo (String.valueOf (url.getValue ()), String.valueOf (name.getValue ()), String.valueOf (username.getValue ()), String.valueOf (date.getValue ()));
postInfos.add (postInfo);
}
baseAdapter.notifyDataSetChanged ();
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText (WallActivity.this, "Error 411: " + databaseError.getMessage (), Toast.LENGTH_SHORT).show ();
}
});
}
}
When I get all the data from getData() function I update my Array Adapter but after updating real size of the array list comes out to be 7 but the getView function takes the value of i from 0 to 2 only. It is not adding all the values from the ArrayList and it is showing same values again and again rather than showing different values.This is the log when the screen loads as I have added Log.e in getView:
04-06 13:04:26.797 10246-10246/lifeline.learn.com.hotornot E/Value of i: 0
04-06 13:04:26.804 10246-10246/lifeline.learn.com.hotornot E/Value of i: 1
04-06 13:04:26.814 10246-10246/lifeline.learn.com.hotornot E/Value of i: 2
It is not going over 2. But when I Log in getCount it returns 7.
Currently, your adapter's getCount() returns the size of urls.size (); but you are passing other 2 arraylists as well, which will only take the size of urls arraylist.
If you pass an Arraylist<UserObject>, you could add all the data to this object and then return the size as userObjects.size();
So the better approach would be to create an object, say UserObject and create an arraylist with this object like Arraylist<UserObject>
UserObject.java
public class UserObject {
String urls;
String names;
String usernames;
String dates;
public UserObject(String urls, String names, String usernames, String dates) {
this.urls = urls;
this.names = names;
this.usernames = usernames;
this.dates = dates;
}
}
Declare an arraylist
ArrayList<UserObject> userData=new ArrayList<>();
Now, change like this
public void onDataChange(DataSnapshot dataSnapshot) {
DataSnapshot posts = dataSnapshot.child ("Posts");
for (DataSnapshot time: posts.getChildren ()){
DataSnapshot url = time.child ("Url");
DataSnapshot name = time.child ("Name");
DataSnapshot username = time.child ("Username");
DataSnapshot date = time.child ("Date");
UserObject user=new UserObject(String.valueOf (url.getValue ()),String.valueOf (name.getValue ()),String.valueOf (username.getValue ()),String.valueOf (date.getValue ()));
userData.add(user);
}
baseAdapter.notifyDataSetChanged ();
}
Your adapter constructor will be like this
public SackViewAdapter(#NonNull Context context, int resource,ArrayList<UserObject> userObjects)
Please do not call these in getData()
You have already initialised it onCreate(), and addValueEventListener is called everytime there is a change
urls.clear ();
usernames.clear ();
dates.clear ();
times.clear ();
Also Its better if you use custom object arraylist rather than using three separate lists of type string and manage them
check your url size if their size two then take only 0 to 2.
because you add in adapter in size..
#Override
public int getCount() {
return urls.size (); // in that provide large size of your data.
}
then after when you bind adapter then after used ..
notifyDataSetChanged ();

Invert ListView Order and Display Without Scrolling

I am trying to invert a ListView so that the most recent items appear first. I have seen results that state to modify the getItem() method, however that requires me scrolling down and scrolling back up to see the new item. Is there a way to have the item appear at the top of the list without requiring the need to scroll?
public class ListAdapter extends ArrayAdapter<Comments> {
Firebase BaseRef = new Firebase(FIREBASE_URL);
Firebase PollsRef = mBaseRef.child(POLLS_LABEL);
Firebase UpdateRef = mPollsRef.child(mCurrentDateString).child(String.valueOf(mPollIndex + 1));
Firebase CommentsRef = mUpdateRef.child(COMMENTS_LABEL);
int pollCommentCount;
public ListAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
public ListAdapter(Context context, int resource, List<Comments> items) {
super(context, resource, items);
}
#Override
public int getCount() {
CommentsRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
pollCommentCount = (int) dataSnapshot.getChildrenCount();
Log.v("POLL_COMMENT_COUNT", "The poll comment count is " + pollCommentCount);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
return pollCommentCount;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.individual_comment, null);
}
Comments p = getItem(position);
if (p != null) {
TextView userID = (TextView) v.findViewById(R.id.user_ID);
TextView userComment = (TextView) v.findViewById(R.id.user_comment);
if (userID != null) {
userID.setText(p.getUserID());
}
if (userComment != null) {
userComment.setText(p.getUserComment());
}
}
return v;
}
}
You can sort the Comment list before creating your adapter. This way they are already in the order you want them to be in. I don't know what variable the Comment object contains that lets you know when it was modified, but assuming it is a date, you can sort the list like this:
Collections.sort(commentsList, new Comparator<Comment>() {
public int compare(Comment c1, Comment c2) {
return c1.getDate().compareTo(c2.getDate());
}
});
You can also simply reverse the list with Collections.reverse(commentList)
Calling notifyDataSetChanged() should update the list.
I realized that the .add() method actually inserts the item at a specific index. If I am always adding new items to index(0), then the items will naturally appear in reverse order.
I thought Google would have been more intuitive with the Android code and allowed for an insert() method, but the add() method at index(o) serves the purpose:
mUpdateRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
setImage(dataSnapshot);
setQuestion(dataSnapshot);
createInitialCommentIDArray(dataSnapshot);
mNumberOfCommentsAtPoll = (int) dataSnapshot.child(COMMENTS_LABEL).getChildrenCount();
for (int i = 0; i < mNumberOfCommentsAtPoll; i++) {
String commentID = (String) dataSnapshot.child(COMMENTS_LABEL).child(mCommentIDArrayList.get(i)).child("COMMENT").getValue();
Log.v("COMMENT_ID", "The comment ID is " + commentID);
String userID = (String) dataSnapshot.child(COMMENTS_LABEL).child(mCommentIDArrayList.get(i)).child("USER_ID").getValue();
Log.v("USER_ID", "The user ID is " + userID);
mCommentArrayList.add(0 , new Comments(mUserAvatar, userID, commentID));
mCommentAdapter.notifyDataSetChanged();
}
}

Categories