RecyclerView: No adapter attached; skipping layout error using Firebase in Fragments - android

I am new to Firebase and just used it today for our app. I have successfully inserted the items to my Firebase console. Now I want these items to display in my Recyclerview using Fragments.
I have experienced this error since morning and exhausted all the information but nothing seems to work for me.
Please check this code and enlighten me what seems to be the problem:
This my Category model
package com.example.devcash.Object;
public class Category {
public String category_name;
public Category(){
}
public Category(String category_name){
this.category_name = category_name;
}
public String getCategory_name() {
return category_name;
}
public void setCategory_name(String category_name) {
this.category_name = category_name;
}
}
CategoriesFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_categories, container, false);
//
categoryrecyclerView = (RecyclerView) view.findViewById(R.id.catrecyclerview);
categoryrecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
catlist = new ArrayList<Category>();
reference = FirebaseDatabase.getInstance().getReference().child("Category");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren()){
Category c = dataSnapshot1.getValue(Category.class);
catlist.add(c);
}
adapter = new CategoryAdapter(getContext(), catlist);
categoryrecyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getContext(), "Something is wrong, please try that again.", Toast.LENGTH_SHORT).show();
}
});
return view;
}
AddCategory
public class AddCategoryActivity extends AppCompatActivity {
private DatabaseReference firebaseDatabase;
private FirebaseDatabase firebaseInstance;
private String CategoryId;
TextInputEditText categoryName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_category);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
categoryName = (TextInputEditText) findViewById(R.id.text_categoryname);
firebaseInstance = FirebaseDatabase.getInstance();
firebaseDatabase = firebaseInstance.getReference("DataDevcash");
CategoryId = firebaseDatabase.push().getKey();
}
public void addCategory (String categoryName){
Category category = new Category(categoryName);
firebaseDatabase.child("Category").child(CategoryId).setValue(category);
}
public void insertCategory(){
addCategory(categoryName.getText().toString().trim());
Toast.makeText(getApplicationContext(), "Category Successfully Added!", Toast.LENGTH_SHORT).show();
finish();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home){
onBackPressed();
return true;
}else if(id == R.id.action_save){ //if SAVE is clicked
insertCategory();
}
return super.onOptionsItemSelected(item);
}
}
CategoryAdapter
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder> {
Context context;
ArrayList<Category> categoryArrayList;
public CategoryAdapter(Context c, ArrayList<Category> categories){
context = c;
categoryArrayList = categories;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.customlayout_category, viewGroup, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
viewHolder.categoryname.setText(categoryArrayList.get(i).getCategory_name());
}
#Override
public int getItemCount() {
return categoryArrayList.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView categoryname;
public ViewHolder(#NonNull View itemView) {
super(itemView);
categoryname = (TextView) itemView.findViewById(R.id.txtcategory_name);
}
}
}
fragment_categories.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/catrecyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="1dp" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/addcategories_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_add"
android:tint="#color/whiteBG"
android:backgroundTint="#color/colorPrimary"/>
</FrameLayout>
Logcat
RecyclerView: No adapter attached; skipping layout
When I try to move my FirebaseDatabase code from onCreateView to onCreate, I will get this error from my logcat.
Logcat
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference
at com.example.devcash.Fragments.CategoriesFragment.onCreate
I have also tried to change the layout_height from match_parent to wrap_content and vice versa but still the items will not show..

The first logcat is simply a warning saying that .setAdapter has not been called on your recyclerView hence nothing would be loaded to it. This is probably because the overridden method onDataChange where you added setAdapter trigger was never called.
The second logcat is an error telling you that you tried to access the RecyclerView before it is initialized. Why? Because you are calling from the wrong method block. Check android fragment lifecycle for more info
To fix both issues refactor your code like below
-- Initialize your adapter and recyclerView only once. i.e inside onCreateView block
catlist = new ArrayList<Category>();
adapter = new CategoryAdapter(getActivity(), catlist);
categoryrecyclerView.setAdapter(adapter);
-- Call notifyDataSetChanged on the adapter anytime the value of catlist changes. Add the below code inside onDataChange callback method
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren()){
Category c = dataSnapshot1.getValue(Category.class);
catlist.add(c);
}
adapter.notifyDataSetChanged();
// adapter = new CategoryAdapter(getContext(), catlist);
// categoryrecyclerView.setAdapter(adapter);
}
You can verify if your implementation is right by adding some dummy data to catlist
//call this any where and if it works then be rest assured
//that no data is returned from your firebase reference
catlist.add(new Category("Sample Category"));
adapter.notifyDataSetChanged();

try this
CategoryAdapter adapter = new CategoryAdapter(getContext());
categoryrecyclerView.setLayoutManager(new
LinearLayoutManager(getContext()));
categoryrecyclerView.setAdapter(adapter );
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren()){
Category c = dataSnapshot1.getValue(Category.class);
catlist.add(c);
}
adapter.pushData(catlist);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getContext(), "Something is wrong, please try that
again.", Toast.LENGTH_SHORT).show();
}
});
inside your adapter add this method
public void pushData(List<Category> list){
this.list.clear();
this.list.addAll(list);
notifyDataSetChanged();
}

CategoryAdapter adapter = new CategoryAdapter(getactivity(),catlist);
categoryrecyclerView.setLayoutManager(new
LinearLayoutManager(getactivity()));
categoryrecyclerView.setAdapter(adapter );
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
catlist.clear();
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren()){
Category c = dataSnapshot1.getValue(Category.class);
catlist.add(c);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getContext(), "Something is wrong, please try that
again.", Toast.LENGTH_SHORT).show();
}
});
change your adapter with attached array list.Get value from it.

Related

Getting data from firebase but not showing in recyclerview

I am new in android development. I am trying to create list of firebase data. so i have created a recyclerview and represent the data in recyclerview.
I have featched data from firebase and assign to adapter class. but data is not showing in recyclerview.
Fragment Class
public class HomeFragment extends Fragment {
DatabaseReference reference;
RecyclerView recyclerView;
ArrayList<Carmodel> list = new ArrayList<>();;
CarAdapter adapter;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.recyclerview, container, false);
recyclerView = (RecyclerView) root.findViewById(R.id.recycler);
recyclerView.setLayoutManager( new LinearLayoutManager(getContext()));
reference = FirebaseDatabase.getInstance().getReference().child("AddCar");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Carmodel p = dataSnapshot1.getValue(Carmodel.class);
Log.e("Get Data", p.getCarName());
list.add(p);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(getActivity(), "Opsss.... Something is wrong", Toast.LENGTH_SHORT).show();
}
});
adapter = new CarAdapter(getContext(), list);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
return root;
}
}
Adapert Class
public class CarAdapter extends RecyclerView.Adapter<CarAdapter.MyViewHolder> {
Context context;
ArrayList<Carmodel> profiles;
public CarAdapter(Context c , ArrayList<Carmodel> p)
{
context = c;
profiles = p;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.fragment_admin_home, parent, false));
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.name.setText(profiles.get(position).getCarName());
holder.seater.setText(profiles.get(position).getSeater());
holder.price.setText(profiles.get(position).getPrice());
holder.status.setText(profiles.get(position).getAvailable());
Picasso.get().load(profiles.get(position).getImageURL()).into(holder.car_image);
}
#Override
public int getItemCount() {
return profiles.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder
{
TextView name,seater,price, status;
ImageView car_image;
#SuppressLint("CutPasteId")
public MyViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.CarName);
seater = (TextView) itemView.findViewById(R.id.Seater);
price = (TextView) itemView.findViewById(R.id.Seater);
car_image = (ImageView) itemView.findViewById(R.id.imageView);
status = (TextView) itemView.findViewById(R.id.Status);
}
}
Carmodel p = dataSnapshot1.getValue(Carmodel.class);
make you sure it is (p) not empty
You are notifying your adapter in wrong time for data change
adapter = new CarAdapter(getContext(), list);
recyclerView.setAdapter(adapter);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Carmodel p = dataSnapshot1.getValue(Carmodel.class);
Log.e("Get Data", p.getCarName());
list.add(p);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(getActivity(), "Opsss.... Something is wrong", Toast.LENGTH_SHORT).show();
}
});
Please modify your method like this

Recyclerview fetch existing data after delete an item from adapter and does not update properly

I try to implement a friend request feature in the fragment using custom adapter with firebase database. The problem is when a user accepts or delete someone request, it deletes from firebase but not properly update in the RecyclerView. this problems occurred in only runtime. If I refresh the page then my problem goes away.
Let I have two friend request. If I delete 2nd data then 2nd data will gone from RecyclerView but the problem is RecyclerView shows 1st data doubles. and if I delete 1st data then 1st data goes in the 2nd row and 2nd data came into the first row.
here is my database screenshot
Fragment class-
public class NotificationFragment extends Fragment {
private RecyclerView NotificationRecyclerView;
private NotificationAdapter adapter;
private List<Friend> friendList;
public NotificationFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_notification, container, false);
NotificationRecyclerView = view.findViewById(R.id.NotificationRecyclerView);
NotificationRecyclerView.setHasFixedSize(true);
LinearLayoutManager LayoutManager = new LinearLayoutManager(getContext());
NotificationRecyclerView.setLayoutManager(LayoutManager);
friendList = new ArrayList<>();
adapter = new NotificationAdapter(getContext(), friendList);
NotificationRecyclerView.setAdapter(adapter);
readAllNotification();
return view;
}
private void readAllNotification() {
final FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("FriendRequest");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Friend friend = snapshot.getValue(Friend.class);
if (firebaseUser.getUid().equals(friend.getReceiverID())) {
friendList.add(friend);
}
}
Collections.reverse(friendList);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
Custom Adapter -
public class NotificationAdapter extends RecyclerView.Adapter<NotificationAdapter.NotificationViewHolder> {
private Context context;
private List<Friend> friendList;
public NotificationAdapter(Context context, List<Friend> friendList) {
this.context = context;
this.friendList = friendList;
}
#NonNull
#Override
public NotificationViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.single_notification_item, parent, false);
return new NotificationAdapter.NotificationViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final NotificationViewHolder holder, final int position) {
final Friend friend = friendList.get(position);
getUserInfo(holder.profileImage, holder.NotificationUserName, friend.getSenderID());
holder.cancelRequestButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseDatabase.getInstance().getReference("FriendRequest")
.child(friend.getRequestID()).removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
removeItem(position);
Toast.makeText(context, "removed", Toast.LENGTH_SHORT).show();
}
});
}
});
}
public void removeItem(int position) {
friendList.remove(position);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return friendList.size();
}
private void getUserInfo(final CircleImageView prfileImage, final TextView NotificationUserName, String senderID) {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Users").child(senderID);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Users users = dataSnapshot.getValue(Users.class);
NotificationUserName.setText(users.getUserName());
Picasso.with(context).load(users.getImageUrl()).into(prfileImage);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
public class NotificationViewHolder extends RecyclerView.ViewHolder {
private TextView NotificationUserName;
private Button cancelRequestButton;
private CircleImageView profileImage;
public NotificationViewHolder(#NonNull View itemView) {
super(itemView);
NotificationUserName = itemView.findViewById(R.id.NotificationUserName);
cancelRequestButton = itemView.findViewById(R.id.cancelRequestBtn);
profileImage = itemView.findViewById(R.id.profileImage);
}
}
}
My APP Problems screenshot -
let I have two request
1) if I delete 2nd data 1st data show doubles:
2) if I delete 1st data, 1st data goes into 2nd row and 2nd data came into 1st row:
Replace
removeItem(position);
with
removeItem(holder.getAdapterPosition());
You initialize your recyclerView and adapter in onCreateView which was not appropriate.You have to override the method onViewCreated then initialize your recyclerView and adapter.try like this
public class NotificationFragment extends Fragment {
private RecyclerView NotificationRecyclerView;
private NotificationAdapter adapter;
private List<Friend> friendList;
public NotificationFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_notification, container, false);
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
NotificationRecyclerView = view.findViewById(R.id.NotificationRecyclerView);
NotificationRecyclerView.setHasFixedSize(true);
LinearLayoutManager LayoutManager = new LinearLayoutManager(getContext());
NotificationRecyclerView.setLayoutManager(LayoutManager);
friendList = new ArrayList<>();
adapter = new NotificationAdapter(getContext(), friendList);
NotificationRecyclerView.setAdapter(adapter);
readAllNotification();
}
private void readAllNotification() {
final FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("FriendRequest");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Friend friend = snapshot.getValue(Friend.class);
if (firebaseUser.getUid().equals(friend.getReceiverID())) {
friendList.add(friend);
}
}
Collections.reverse(friendList);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Ok I just noticed you passed a parameter in removeItem method using holder.getAdapterPosition() which is causing your problem.Try to pass the position which is provided by public void onBindViewHolder(#NonNull final NotificationViewHolder holder, final int position).So the basic error is when you are in onBindViewHolder you don't need to use holder.getAdapterPosition() because onBindViewHolder already giving you the position
In your removeItem method use notifyDataSetChanged instead of notifyItemRemoved(position)
try like this
#Override
public void onBindViewHolder(#NonNull final NotificationViewHolder holder, final int position) {
final Friend friend = friendList.get(position);
holder.cancelRequestButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseDatabase.getInstance().getReference("FriendRequest").child(friend.getRequestID()).removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
removeItem(position);
Toast.makeText(context, "removed", Toast.LENGTH_SHORT).show();
}
});
}
});
}
public void removeItem(int position) {
friendList.remove(position);
notifyDataSetChanged();
}

How do I make recyclerView that retrives data from firebase, using getKey()?

I would like to know how can I do a recyclerView that shows data that I got from this database reference:
Salas= new ArrayList<String>();
DatabaseReference referenceSalas = FirebaseDatabase.getInstance().getReference("salas/");
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("usuarios/");
FirebaseAuth autenticacao = FirebaseAuth.getInstance();
String emailUsu = autenticacao.getCurrentUser().getEmail();
reference.orderByChild("email").equalTo(emailUsu).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot datas : dataSnapshot.getChildren()) {
nomeProf = datas.child("nome").getValue().toString();
referenceSalas.orderByChild("nomeProf").equalTo(nomeProf).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot datas : dataSnapshot.getChildren()) {
Salas.add(datas.getKey());
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
I tried to do the RecyclerView like this:
public class salasFragment extends Fragment {
private RecyclerView mRecycleViewSalas;
private adapterSalas adapterSalas;
private ArrayList<salas> listaSalas= new ArrayList<>();
private LinearLayoutManager linearLayoutManager;
private TextView txtSalas, txtTeste;
private String nomeProf;
private String teste="", piru;
private DatabaseReference reference = FirebaseDatabase.getInstance().getReference("usuarios/");
private DatabaseReference referenceSalas = FirebaseDatabase.getInstance().getReference("salas/");
private ValueEventListener valueEventListenerSalas;
ArrayList<String> salasAula = new ArrayList<String>();
public salasFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_salas, container, false);
final Context context = view.getContext();
txtSalas= view.findViewById(R.id.txtSalas);
txtTeste= view.findViewById(R.id.txtTeste);
mRecycleViewSalas= view.findViewById(R.id.recyclerSalas);
adapterSalas= new adapterSalas(listaSalas, context);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context);
mRecycleViewSalas.setLayoutManager(layoutManager);
mRecycleViewSalas.setHasFixedSize(true);
mRecycleViewSalas.setAdapter(adapterSalas);
return view; }
#Override
public void onStart() {
super.onStart();
recuperarSalas();
}
#Override
public void onStop() {
super.onStop();
reference.removeEventListener(valueEventListenerSalas);
}
public void recuperarSalas(){
FirebaseAuth autenticacao = FirebaseAuth.getInstance();
String emailUsu = autenticacao.getCurrentUser().getEmail();
valueEventListenerSalas = reference.orderByChild("email").equalTo(emailUsu).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot datas : dataSnapshot.getChildren()) {
nomeProf = datas.child("nome").getValue().toString();
referenceSalas.orderByChild("nomeProf").equalTo(nomeProf).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot datas : dataSnapshot.getChildren()) {
salas salas=datas.getKey(salas.class);
listaSalas.add(salas);
}
adapterSalas.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
my adapter:
public class adapterSalas extends RecyclerView.Adapter<adapterSalas.myViewHolder> {
private List<salas> Salas;
private Context context;
public adapterSalas(List<salas> listaSalas, Context c ) {
this.Salas= listaSalas;
this.context = c;
}
#NonNull
#Override
public myViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
View itemLista = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_salas, parent, false);
return new myViewHolder(itemLista);
}
#Override
public void onBindViewHolder(#NonNull myViewHolder holder, int position) {
salas sala = Salas.get(position);
holder.btn1.setText(sala.getPrimeiro());
}
#Override
public int getItemCount() {
return Salas.size();
}
public class myViewHolder extends RecyclerView.ViewHolder{
Button btn1;
public myViewHolder(#NonNull View itemView) {
super(itemView);
btn1 = itemView.findViewById(R.id.btn1);
}
}
}
Although this line "salas salas=datas.getKey(salas.class);" does not work properly when I use "getKey", It only works when "getValue" is used. There is no way of me doing this project with "getValue" instead of "getKey". So there is any way that can make this recyclerView works properly with "getKey" ?
Have you got the data from the firebase already?
If you got the data in an arraylist already, simply plug it in an adapter (you will need to create a RecyclerView adapter, a class to describe the value of each RecyclerView items) and set it to the RecyclerView and you are good to go!
You can use FirebasRecyclerAdapter as you recyclerView adapter. check out this link for a guide on how to use it.
https://medium.com/android-grid/how-to-use-firebaserecycleradpater-with-latest-firebase-dependencies-in-android-aff7a33adb8b

Issue with FirebaseRecyclerAdapter, on a null object reference when delete data

The display from the Firebase database works fine, but when I try to delete an item from the database, the application crashes, although the deletion occurs. Writes on a null object reference in the string:
String postDescription = dataSnapshot.child("desc").getValue().toString();
Here is my code:
public class PostFragment extends Fragment {
private RecyclerView recyclerPost;
private DatabaseReference postReference;
private View view;
private LinearLayoutManager layoutManager;
public PostFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_post, container, false);
recyclerPost = view.findViewById(R.id.recycler_post);
postReference = FirebaseDatabase.getInstance().getReference().child("Posts");
postReference.keepSynced(true);
layoutManager = new LinearLayoutManager(getContext());
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
recyclerPost.setHasFixedSize(true);
recyclerPost.setLayoutManager(layoutManager);
return view;
}
#Override
public void onStart() {
super.onStart();
Query query = postReference.orderByChild("timestamp");
FirebaseRecyclerOptions<Posts> options =
new FirebaseRecyclerOptions.Builder<Posts>()
.setQuery(query, Posts.class)
.build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Posts, PostViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final PostViewHolder holder, int position, #NonNull final Posts model) {
final String postId = getRef(position).getKey();
postReference.child(postId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String postDescription = dataSnapshot.child("desc").getValue().toString();
holder.postDesc.setText(postDescription);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
holder.delBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
postReference.child(postId).removeValue();
}
});
}
#NonNull
#Override
public PostViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int position) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.blog_item, viewGroup, false);
return new PostViewHolder(view);
}
};
adapter.startListening();
recyclerPost.setAdapter(adapter);
}
public class PostViewHolder extends RecyclerView.ViewHolder {
private TextView postDesc;
private Button delBtn;
private View view;
public PostViewHolder(#NonNull View itemView) {
super(itemView);
view = itemView;
postDesc = (TextView) view.findViewById(R.id.post_description);
delBtn = (Button) view.findViewById(R.id.del_post_btn);
}
}
}
Please tell me the solution to this problem.
You can try the following:
postReference.child(postId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
String postDescription = dataSnapshot.child("desc").getValue().toString();
holder.postDesc.setText(postDescription);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
You can use the method exists():
public boolean exists ()
Returns true if the snapshot contains a non-null value.
It will check if the datasnapshot is in the
database, if it is not in the database then you can add a snackbar or a toast.
More information here:
https://firebase.google.com/docs/reference/android/com/google/firebase/database/DataSnapshot#exists()
Every time a post is added to the adapter/list view, you now create a listener with addValueEventListener in your onBindViewHolder. This listener gets the value from the database, and then keeps listening for changes until you remove it. Since you never remove these listeners, over time they add up and things likely get out of sync.
The simplest solution is to use addListenerForSingleValueEvent:
#Override
protected void onBindViewHolder(#NonNull final PostViewHolder holder, int position, #NonNull final Posts model) {
final String postId = getRef(position).getKey();
postReference.child(postId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String postDescription = dataSnapshot.child("desc").getValue().toString();
holder.postDesc.setText(postDescription);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
When you use addListenerForSingleValueEvent, the listener is removed right after onDataChange fires for the first time.

Android - Load data from Firebase Database in Fragment

I have a NavigationDrawer activity which is using fragments. In one of my fragments I want to load data from the Firebase database to a RecyclerView.
So I have an ArrayList for the objects I have stored in the database. Then I add a ValueEventListener to my database reference where I add the objects from the database to the array list. And then I give the ArrayList to the RecyclerView Adapter which should create the list with my objects.
When I use addListenerForSingleValueEvent it is never working, I always get an empty RecyclerView. When I use addValueEventListener it is working neither at the start, but when I switch the orientation of my phone to landscape the data suddenly appears. And if I go back to the normal orientation it is still there. But not at the start when I open the fragment.
Here is my code of the fragment class:
public class LogFragment extends Fragment {
private RecyclerView recyclerView;
private RecyclerView.Adapter rvAdapter;
private RecyclerView.LayoutManager rvLayoutManager;
private ArrayList<LogEntry> entries;
private DatabaseReference databaseReference;
private DatabaseReference logReference;
private FirebaseAuth firebaseAuth;
private FirebaseUser firebaseUser;
public LogFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_log, container, false);
databaseReference = FirebaseDatabase.getInstance().getReference();
firebaseAuth = FirebaseAuth.getInstance();
firebaseUser = firebaseAuth.getCurrentUser();
loadEntries();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
rvLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(rvLayoutManager);
rvAdapter = new RvAdapter(entries);
recyclerView.setAdapter(rvAdapter);
// Inflate the layout for this fragment
return rootView;
}
private void loadEntries(){
entries = new ArrayList<>();
logReference = databaseReference.child("log").child(firebaseUser.getUid());
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
entries.add(ds.getValue(LogEntry.class));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w("LogFragment", "loadLog:onCancelled", databaseError.toException());
}
};
logbuchReference.addValueEventListener(valueEventListener);
}
}
And here is my RvAdapter.java:
public class RvAdapter extends RecyclerView.Adapter<RvAdapter.MyViewHolder> {
private ArrayList<LogEntry> entries;
public RvAdapter(ArrayList<LogEntry> entries){
this.entries = entries;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.log_entry_item, null);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
holder.tvAction.setText(entries.get(position).action);
holder.tvDate.setText(dateFormat.format(entries.get(position).date)+"\n"+timeFormat.format(entries.get(position).date));
holder.ivIcon.setImageResource(entries.get(position).icon);
holder.itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
// Do something
}
});
}
#Override
public int getItemCount() {
return entries.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvAction, tvDate;
ImageView ivIcon;
public MyViewHolder(View itemView) {
super(itemView);
tvAction = (TextView) itemView.findViewById(R.id.tvAction);
tvDate = (TextView) itemView.findViewById(R.id.tvDate);
ivIcon = (ImageView) itemView.findViewById(R.id.ivIcon);
}
}
}
And here my LogEntry.java:
public class LogEntry {
public String action;
public Date date;
public int icon;
public String message;
public LogEntry() {}
public LogEntry(String action, Date date, int icon, String message) {
this.action = action;
this.date = date;
this.icon = icon;
this.message = message;
}
}
Someone know what could be the problem?
EDIT:
When I System.out.prinln the ArrayList right after the for() I get the data. So loading the data from the database is working. But presenting the data is not working.
Firebase is asynchronous. Set or notify the adapter from within the callback.
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
entries.add(ds.getValue(LogEntry.class));
}
// Declare adapter and set here
// OR... adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w("LogFragment", "loadLog:onCancelled", databaseError.toException());
}
};
In more detail,
loadEntries(); // ... Doing stuff in the background
recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
rvLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(rvLayoutManager);
rvAdapter = new RvAdapter(entries); // This is still empty, probably
recyclerView.setAdapter(rvAdapter);
// entries.add() called later, but adapter never notified
You can use https://github.com/firebase/FirebaseUI-Android to solve this problem.
follow a little code to help you...
ListView messagesView = (ListView) findViewById(R.id.messages_list);
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
mAdapter = new FirebaseListAdapter<Chat>(this, Chat.class, android.R.layout.two_line_list_item, ref) {
#Override
protected void populateView(View view, Chat chatMessage, int position) {
((TextView)view.findViewById(android.R.id.text1)).setText(chatMessage.getName());
((TextView)view.findViewById(android.R.id.text2)).setText(chatMessage.getText());
}
};
messagesView.setAdapter(mAdapter);
Good luck!!!

Categories

Resources