I have a regular RecyclerView in FRA I set up in onbindviewholder class. İt turns longth as you see in app there is a space for all items normally I should see there reply text but just one can see.
dbreply.child(post_key).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds:snapshot.getChildren()) {
for (DataSnapshot snapshot1:ds.getChildren()) {
reply data = snapshot1.getValue(reply.class);
list.add(data);
holder.rcv.setLayoutManager(new LinearLayoutManager(getContext()));
myAdapter = new MyAdapter(getContext(), list);
holder.rcv.setAdapter(myAdapter);
myAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) { }});
You are getting that behavior because you are creating a new instance of MyAdapter at each iteration of the inner loop. What you should is to get all those 4 lines of code out of the loop, as you can see below:
for (DataSnapshot ds:snapshot.getChildren()) {
for (DataSnapshot snapshot1:ds.getChildren()) {
reply data = snapshot1.getValue(reply.class);
list.add(data);
}
holder.rcv.setLayoutManager(new LinearLayoutManager(getContext()));
myAdapter = new MyAdapter(getContext(), list);
holder.rcv.setAdapter(myAdapter);
myAdapter.notifyDataSetChanged();
}
Related
I am trying to fill a spinner with categories, I manage to iterate every category in my database and add it to the spinner but I need to fetch only distinct values, see this image;
This is my code;
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
final List<String> categorySpinner = new ArrayList<>();
for (DataSnapshot childSpinner : snapshot.getChildren()) {
String spinnerCat = childSpinner.child("category").getValue(String.class);
categorySpinner.add(spinnerCat);
}
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(LineChartActivity.this, R.layout.spinner_item, categorySpinner);
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_item);
spinner_2.setAdapter(arrayAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
It's simple, simply change the line:
categorySpinner.add(spinnerCat);
to
if (!categorySpinner.contains(spinnerCat)) {
categorySpinner.add(spinnerCat);
}
Happy coding.
I have a root node named "Posts" in the Firebase Realtime Database. Inside that, I have two nodes called "ImagePosts" and "TextPosts". And inside "ImagePosts" (and "TextPosts"), I have postIds of various posts. And inside a postID, I have all the details of that particular post including postedAt (post time).
What I want to do is that write a query to fetch data from "ImagePosts" and "TextPosts" TOGETHER AND display all the posts in descending/reverse order (that is, the post which is posted last/recently should show up at the top in my Recycler View according to "postedAt").
Please click here to see database structure
To achieve this, I created a single model named Post and two adapters named "PostAdapter" and "TextPostAdapter". And my Recycler View is "DashboardRV". What have I tried so far:
Code of Home Fragment:
public class HomeFragment extends Fragment {
ShimmerRecyclerView dashboardRV;
ArrayList<Post> postList;
public HomeFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
dashboardRV = view.findViewById(R.id.dashboardRv);
dashboardRV.showShimmerAdapter();
postList = new ArrayList<>();
PostAdapter postAdapter = new PostAdapter(postList, getContext());
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
dashboardRV.setLayoutManager(layoutManager);
dashboardRV.addItemDecoration(new DividerItemDecoration(dashboardRV.getContext(), DividerItemDecoration.VERTICAL));
dashboardRV.setNestedScrollingEnabled(false);
dashboardRV.setAdapter(postAdapter);
postList.clear();
database.getReference()
.child("Posts")
.child("ImagePosts")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
}
Collections.reverse(postList);
dashboardRV.hideShimmerAdapter();
postAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
database.getReference()
.child("Posts")
.child("TextPosts")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
postList.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
}
Collections.reverse(postList);
dashboardRV.hideShimmerAdapter();
textPostAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
But the problem with this approach is that it doesn't display all the "TextPosts" and "ImagePosts" together. It only shows all the image posts on the opening app, then when I change fragment and come back, then it displays all text posts. I am just stuck here.
Use only one adapter for one recycler view at a time:
Here is the code for a single adapter with both (image and text posts):
postList = new ArrayList<>();
PostAdapter postAdapter = new PostAdapter(postList, getContext());
dashboardRV.setAdapter(postAdapter);
// call clear before refreshing the list
postList.clear();
database.getReference()
.child("Posts")
.child("ImagePosts")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()){
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
}
Collections.sort(postList);
dashboardRV.hideShimmerAdapter();
postAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
database.getReference()
.child("Posts")
.child("TextPosts")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren())
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
}
Collections.sort(postList);
dashboardRV.hideShimmerAdapter();
postAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
// make Post class implemented comparable to sort the list after fetching:
// A class 'Post' that implements Comparable
class Post implements Comparable<Post>
{
...
// Used to sort posts by their postedAt
public int compareTo(Post p)
{
return this.postedAt - p.postedAt;
}
...
}
This link will help to explore how to sort according to postedAt: Using Comparable
To merge 2 separate Firebase Realtime Database requests locally, I recommend you to use Tasks.whenAllSuccess() method. You can achieve this, using the following lines of code:
DatabaseReference imagePostsRef = database.getReference()
.child("Posts")
.child("ImagePosts");
DatabaseReference textPostsRef = database.getReference()
.child("Posts")
.child("TextPosts");
Task firstTask = imagePostsRef.get();
Task secondTask = textPostsRef.get();
Task combinedTask = Tasks.whenAllSuccess(firstTask, secondTask).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
#Override
public void onSuccess(List<Object> list) {
//Do what you need to do with your list
}
});
As you can see, when overriding the "onSuccess()" method the result is a list of objects. In the end, simply map each object from the list into an object of type Post, and pass the new list to a single adapter.
This is my firebase database:
I want to display the value of the auto-generated id given by the push method
this is my code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_recycler_view);
FirebaseApp.initializeApp(this);
recyclerView = findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
String key = newRef.getKey();
preRef.child(key).get();
list = new ArrayList<>();
myAdapter = new MyAdapter(this, list);
recyclerView.setAdapter(myAdapter);
preRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Calendar calendar = dataSnapshot.getValue(Calendar.class);
list.add(calendar);
}
myAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
I cant display the value of the Uid can someone please help me?
To display the list of dates, you can do:
DatabaseReference actlogRef = FirebaseDatabase.getInstance().getReference("ActLog");
actlogRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.child("date").getChildren()) {
String date = dataSnapshot.getValue(String.class);
list.add(date);
}
myAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // never ignore errors
}
});
For this, list will have to be a list of strings, as that's what you store in the database. If you must use a list of Date objects, have a look at questions about parsing a data from a string in java.
In my app I use the firebase database. There are questions and the corresponding comments stored in seperat nodes. Now I try to get the questions with the one listener and access the comments with a second listener. Unfortunately I‘m confused by their behavior: the recyclerView always gets an empty questionsList, like the second listener is skipped. But after the recyclerView got the list and the adapter is set up, my LogCat starts printing the questions and the comment information.
But why is the recyclerView populated and used before the for loop that processes the data has finished?
The method to fetch the information:
private void getQuestionsFromDatabase() {
mQuestions.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
questionList = new ArrayList<>();
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
final String title = dataSnapshot1.child("title").getValue().toString();
final String question = dataSnapshot1.child("question").getValue().toString();
final String commentId = dataSnapshot1.child("commentId").getValue().toString();
mComments.child(commentId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
count = dataSnapshot.getChildrenCount();
QuestionModel questionModel = new QuestionModel(title, question, commentId, String.valueOf(count));
questionList.add(questionModel);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Log.d("questionList length: ", String.valueOf(questionList.size()));
recyclerViewAdapter = new RecyclerViewQuestionAdapter(questionList, getActivity());
recyclerViewlayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(recyclerViewlayoutManager);
recyclerView.setAdapter(recyclerViewAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
It is used before, because the onDataChange is asynchronous, which means that the compiler will not wait until data is fetched from the database, instead it will execute the code after the listener. Therefore to solve your problem, you should do the following:
mComments.child(commentId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
count = dataSnapshot.getChildrenCount();
QuestionModel questionModel = new QuestionModel(title, question, commentId, String.valueOf(count));
questionList.add(questionModel);
Log.d("questionList length: ", String.valueOf(questionList.size()));
recyclerViewAdapter = new RecyclerViewQuestionAdapter(questionList, getActivity());
recyclerViewlayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(recyclerViewlayoutManager);
recyclerView.setAdapter(recyclerViewAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
I am trying to get all keys under a Value and generate a popup for them. But I don't get how. I tried a lot of "for" statements but could not figure it out.
My code at the moment:
final FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myRef = database.getReference("Anzeigen");
// Read from the database
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot:dataSnapshot.getChildren())
{
RecyclerView recyclerView = findViewById(R.id.anzeigen_list);
final List<generater> mList = new ArrayList<>();
RecyclerView.Adapter adapter = new generater_anzeigen_setter(this,mList);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mList.add(new generater(Name , Was , Preis));
}
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
This is my database:
try this:
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
final List<generater> mList = new ArrayList<>();
for(DataSnapshot ds:dataSnapshot.getChildren()){
String name,was,preis;
for(DataSnapshot childSnapShot:ds.getChildren()){
if(childSnapShot.getKey().equals("Name")){
name=childSnapShot.getValue().toString();
}
if(childSnapShot.getKey().equals("Was")){
was=childSnapShot.getValue().toString();
}
if(childSnapShot.getKey().equals("Preis")){
preis=childSnapShot.getValue().toString();
}
}
generater generater = new generater(name , was , preis);
mList.add(generater);
}
RecyclerView recyclerView = findViewById(R.id.anzeigen_list);
final List<generater> mList = new ArrayList<>();
RecyclerView.Adapter adapter = new generater_anzeigen_setter(this,mList);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});