Android firebase - why does clicking star always remove one child value? - android

This is FreeboardPost.java
public class FreeboardPost
{
public String imageUrl;
public String uid;
public String author;
public String title;
public String body;
public int starCount = 0;
public Map<String, Boolean> stars = new HashMap<>();
public FreeboardPost()
{
}
public FreeboardPost(String uid, String author, String title, String body, String imageUrl)
{
this.imageUrl = imageUrl;
this.uid = uid;
this.author = author;
this.title = title;
this.body = body;
}
#Exclude
public Map<String, Object> toMap()
{
HashMap<String, Object> result = new HashMap<>();
result.put("image", imageUrl);
result.put("uid", uid);
result.put("author", author);
result.put("title", title);
result.put("body", body);
result.put("starCount", starCount);
result.put("stars", stars);
return result;
}
}
This is FreeboardPostViewHolder.java
public class FreeboardPostViewHolder extends RecyclerView.ViewHolder
{
public TextView freeboardtitleView;
public TextView freeboardauthorView;
public ImageView freeboardstarView;
public TextView freeboardnumStarsView;
public TextView freeboardbodyView;
public CircleImageView freeboardprofileView;
public FreeboardPostViewHolder(View itemView)
{
super(itemView);
freeboardtitleView = (TextView) itemView.findViewById(R.id.freeboard_post_title);
freeboardauthorView = (TextView) itemView.findViewById(R.id.freeboard_post_author);
freeboardstarView = (ImageView)itemView.findViewById(R.id.freeboard_star);
freeboardnumStarsView = (TextView)itemView.findViewById(R.id.freeboard_post_num_stars);
freeboardbodyView = (TextView)itemView.findViewById(R.id.freeboard_post_body);
freeboardprofileView = (CircleImageView)itemView.findViewById(R.id.freeboard_post_author_photo);
}
public void bindToPost(FreeboardPost freeboardpost, View.OnClickListener starClickListener)
{
freeboardtitleView.setText(freeboardpost.title);
freeboardauthorView.setText(freeboardpost.author);
freeboardnumStarsView.setText(String.valueOf(freeboardpost.starCount));
freeboardbodyView.setText(freeboardpost.body);
freeboardstarView.setOnClickListener(starClickListener);
}
}
and this is FreeboardPostListFragment.java
public abstract class FreeboardPostListFragment extends Fragment
{
private static final String TAG = "FreeBoardPostListFragment";
private DatabaseReference mDatabase;
private FirebaseRecyclerAdapter<FreeboardPost, FreeboardPostViewHolder> mAdapter;
private RecyclerView mRecycler;
private LinearLayoutManager mManager;
private DatabaseReference mPostReference;
private ValueEventListener mPostListener;
private String image;
public FreeboardPostListFragment()
{
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.freeboard_fragment_all_posts, container, false);
mDatabase = FirebaseDatabase.getInstance().getReference();
mRecycler = (RecyclerView)rootView.findViewById(R.id.freeboard_messages_list);
mRecycler.setHasFixedSize(true);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
mManager = new LinearLayoutManager(getActivity());
mManager.setReverseLayout(true);
mManager.setStackFromEnd(true);
mRecycler.setLayoutManager(mManager);
Query postsQuery = getQuery(mDatabase);
mAdapter = new FirebaseRecyclerAdapter<FreeboardPost, FreeboardPostViewHolder>(FreeboardPost.class, R.layout.freeboard_item_post, FreeboardPostViewHolder.class, postsQuery)
{
#Override
protected void populateViewHolder(final FreeboardPostViewHolder viewHolder, final FreeboardPost model, final int position)
{
final DatabaseReference postRef = getRef(position);
final String postKey = postRef.getKey();
mPostReference = FirebaseDatabase.getInstance().getReference().child("FreeboardPost").child(postKey);
viewHolder.itemView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Intent intent = new Intent(getActivity(), FreeBoardPostDetailActivity.class);
intent.putExtra(FreeBoardPostDetailActivity.EXTRA_POST_KEY, postKey);
startActivity(intent);
}
});
if(model.stars.containsKey(getUid()))
{
viewHolder.freeboardstarView.setImageResource(R.drawable.ic_toggle_star_24);
}
else
{
viewHolder.freeboardstarView.setImageResource(R.drawable.ic_toggle_star_outline_24);
}
viewHolder.bindToPost(model, new View.OnClickListener()
{
#Override
public void onClick(View starView)
{
DatabaseReference globalPostRef = mDatabase.child("FreeboardPost").child(postRef.getKey());
DatabaseReference userPostRef = mDatabase.child("FreeboardUserPost").child(model.uid).child(postRef.getKey());
onStarClicked(globalPostRef);
onStarClicked(userPostRef);
}
});
}
};
mRecycler.setAdapter(mAdapter);
}
private void onStarClicked(DatabaseReference postRef)
{
postRef.runTransaction(new Transaction.Handler()
{
#Override
public Transaction.Result doTransaction(MutableData mutableData)
{
FreeboardPost p = mutableData.getValue(FreeboardPost.class);
if(p == null)
{
return Transaction.success(mutableData);
}
if(p.stars.containsKey(getUid()))
{
p.starCount = p.starCount - 1;
p.stars.remove(getUid());
}
else
{
p.starCount = p.starCount + 1;
p.stars.put(getUid(), true);
}
mutableData.setValue(p);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot)
{
}
});
}
public String getUid()
{
return FirebaseAuth.getInstance().getCurrentUser().getUid();
}
public abstract Query getQuery(DatabaseReference databaseReference);
}
and this is freeboard_include_post_author.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center_vertical"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/freeboard_post_author_photo"
android:layout_width="40dp"
android:layout_height="40dp"
app:civ_border_width="2dp"
app:civ_border_color="#FF000000">
</de.hdodenhof.circleimageview.CircleImageView>
<TextView
android:id="#+id/freeboard_post_author"
style="#style/Base.TextAppearance.AppCompat.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:gravity="center_vertical"
tools:text="someauthor#email.com" />
</LinearLayout>
and this is freeboard_item_post.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="1dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<ImageView
android:id="#+id/freeboard_post_image"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginRight="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
android:src="#drawable/profile"/>
<RelativeLayout
android:id="#+id/freeboard_text_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#id/freeboard_post_image">
<LinearLayout
android:id="#+id/freeboard_star_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/freeboard_post_author_layout"
android:layout_alignParentRight="true"
android:layout_alignTop="#+id/freeboard_post_author_layout"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="#+id/freeboard_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:background="?attr/selectableItemBackground"
android:src="#drawable/ic_toggle_star_outline_24" />
<TextView
android:id="#+id/freeboard_post_num_stars"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
tools:text="7" />
</LinearLayout>
<include
android:id="#+id/freeboard_post_text"
layout="#layout/freeboard_include_post_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp" />
<include
android:id="#+id/freeboard_post_author_layout"
android:layout_below="#+id/freeboard_post_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/freeboard_include_post_author"
android:layout_marginTop="10dp"
android:layout_alignParentLeft="true" />
</RelativeLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
Thank you so much for reading my long codes. I was having a hard time displaying user's image with star button with it. When I click star, the firebase immediately deletes "image" value from the same child.
This is before I click star
and this is after I click star button.
I am 100% sure there is no code that deletes the child or value.. but why does it remove my image address from the child..? I am so curious about it. Thank you!

You didn't post the code that creates instances of FreeboardPost in the database. I'm guessing that you are using toMap() because it stores the image URL in a field named image, which appears in the database sample you posted.
In your transaction you are using Firebase to serialize/deserialize FreeboardPost. It expects to find the image URL in a field named imageUrl, because that is the public field name in your class. When the node you posted is read, there is no field named imageUrl so the created instance of FreeboardPost has null for that field value. When the instance is written, there is no value written for imageUrlbecause it is null, and the previous database value for image is lost because FreeboardPost has no field with that name.
If you want to use the Firebase capabilities to serialize/deserialize your FreeboardPost, you should use them for all database reads and writes. Using updateMap() or setValue() with a map to write instances and then a POJO class to read risks naming mismatches.

Related

FATAL EXCEPTION: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference getItemCount

I'm just trying to display all images uploaded to Firebase Storage using a recyclerview. Every time I run my app to test out everything my app crashes and when I check the Logcat it keeps telling me Attempt to invoke interface method 'int java.util.List.size()' on a null object reference at com.myapp.yoody.AdapterOne.getItemCount. I'm just wondering what is the null object its referring to. Is it talking about the fact that it's not connecting to firebase? or what is it? I've been trying for days to get this thing to work and I've got nothing. Please help me out here. I hope my question doesn't sound confusing. Here's my code below. Thanks in advance
//Profilepage (The page where the images are supposed to display)
FirebaseAuth firebaseAuth;
FirebaseUser firebaseUser;
TextView name;
DatabaseReference databaseReference;
StorageReference storageReference;
private Context mccontext=ProfileActivity.this;
RecyclerView recyclerView;
AdapterOne adapter1;
String uid;
// Folder path for Firebase Storage.
ImageView imageView;
//List<ImageUploadInfo> list=new ArrayList<>();
ArrayList<ImageUploadInfo> imagesList;
// Folder path for Firebase Storage.
String Storage_Path = "Images/";
// Root Database Name for Firebase Database.
public static final String Database_Path = "Images";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
recyclerView=findViewById(R.id.recyclerView);
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
recyclerView.setHasFixedSize(true);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
overridePendingTransition(R.anim.slide_right, R.anim.slide_left);
adapter1=new AdapterOne(mccontext,imagesList);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter1);
imagesList=new ArrayList<>();
adapter1.notifyDataSetChanged();
//databaseReference=FirebaseDatabase.getInstance().getReference("Users");
uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
// Assign FirebaseStorage instance to storageReference.
storageReference = FirebaseStorage.getInstance().getReference();
// Assign FirebaseDatabase instance with root database name.
databaseReference = FirebaseDatabase.getInstance().getReference(Database_Path);
// Adding Add Value Event Listener to databaseReference.
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot postSnapshot:dataSnapshot.getChildren() ){
ImageUploadInfo imageUploadInfo=postSnapshot.getValue(ImageUploadInfo.class);
imagesList.add(imageUploadInfo);
}
adapter1 = new AdapterOne(getApplicationContext(), imagesList);
recyclerView.setAdapter(adapter1);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
//My Adapter class
public class AdapterOne extends RecyclerView.Adapter<AdapterOne.ViewHolder> {
Context context;
List<ImageUploadInfo> imagesList;
public AdapterOne(Context c, List<ImageUploadInfo> TempList) {
imagesList = TempList;
context = c;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
ImageUploadInfo imageUploadInfo = imagesList.get(position);
Glide.with(context).load(imageUploadInfo.getImageUrl()).into(holder.imageView);
}
#Override
public int getItemCount() {
return imagesList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
imageView=(ImageView) itemView.findViewById(R.id.imageview);
}
}
}
//UploadInfo class
public class ImageUploadInfo {
// public String imageName;
public String imageURL;
public ImageUploadInfo() {} // default constructor that takes no arguments
public ImageUploadInfo( String url) {
this.imageURL= url;
}
public String getImageUrl() {
return imageURL;
}
public void setImageURL(String imageURL) {
this.imageURL = imageURL;
}
}
//CardView class
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
android:orientation="vertical"
>
<GridLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginTop="0dp"
android:alignmentMode="alignMargins"
android:columnCount="1"
android:paddingTop="20dp"
android:columnOrderPreserved="false"
android:rowCount="3">
<!-- 3 -->
<!-- 4 -->
<androidx.cardview.widget.CardView
android:layout_width="350dp"
android:layout_height="320dp"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:layout_marginLeft="6dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="10dp"
app:cardCornerRadius="0dp"
app:cardElevation="0dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:id="#+id/imageview"
/>
<!--
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/imagename"
android:text="Image Name"
/>
-->
</androidx.cardview.widget.CardView>
</GridLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
The problem is that you initialize the list AFTER you send it to adapter. So adapter trying to execute its method on the list which is not exist. Move init lane BEFORE send it in adapter

Fetching chat messages from firestore

I am making a chat section in my app, but the only problem I am facing is that whenever I enter a new message, some of the previous messages getting displayed in the recycler views get erased from the recycler view. But those messages are present in 'firestore'. They are not getting deleted from there but are getting vanished from the recycler view as soon as I enter a new message. When I restart the activity it works perfectly all messages are there.. but the problem only occurs when I enter a new message...and also when I scroll through the 'recyclerview'. Here are the codes...
This is the chatModel class :
import java.io.Serializable;
import java.util.Date;
public class chatModel implements Serializable {
private String Message,sender,Type,id;
private Date Time;
public chatModel()
{
}
public chatModel(String Message, String sender, String type,Date Time ,String id) {
this.Message = Message;
this.sender = sender;
Type = type;
this.Time = Time;
this.id = id;
}
public String getMessage() {
return Message;
}
public void setMessage(String message) {
Message = message;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public Date getTime() {
return Time;
}
public void setTime(Date time) {
Time = time;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
This is the DiscussionActivity class:
public class DiscussionActivity extends AppCompatActivity {
private FirebaseAuth mAuth;
private FirebaseFirestore mFirestore;
private FirebaseStorage mStorage;
private DatabaseReference mDatabase;
private EditText msg;
private Button sendBtn;
private ImageView addDocs;
private Uri imageUri;
private String url;
private RecyclerView mChatContainer;
private List<chatModel> chatList;
private chatAdapter adapter;
private int position=0;
String getMessage,getTitle,getDate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_discussion);
mAuth = FirebaseAuth.getInstance();
mFirestore = FirebaseFirestore.getInstance();
mStorage = FirebaseStorage.getInstance();
mDatabase = FirebaseDatabase.getInstance().getReference();
msg = (EditText)findViewById(R.id.textContent);
sendBtn = (Button)findViewById(R.id.sendMsg);
addDocs = (ImageView)findViewById(R.id.include_documents);
getTitle = getIntent().getExtras().getString("Title");
int getCurrentYear = Calendar.getInstance().get(Calendar.YEAR);
int getCurrentMonth = Calendar.getInstance().get(Calendar.MONTH);
int getCurrentDate = Calendar.getInstance().get(Calendar.DATE);
getDate=getCurrentDate+getCurrentMonth+getCurrentYear+"";
mChatContainer = (RecyclerView)findViewById(R.id.chatContainer);
chatList = new ArrayList<>();
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = msg.getText().toString().trim();
int random = new Random().nextInt();
Map chat = new HashMap();
chat.put("Message",message);
chat.put("sender",mAuth.getCurrentUser().getUid());
chat.put("Time",FieldValue.serverTimestamp());
chat.put("Type","text");
chat.put("id",String.valueOf(random));
mFirestore.collection("Ideas").document(getTitle).collection("Discussions").add(chat).addOnCompleteListener(DiscussionActivity.this, new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if(task.isSuccessful())
{
msg.setText("");
}
}
});
}
});
addDocs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
discussionOptionsSheetDialog obj = new discussionOptionsSheetDialog();
Bundle bundle = new Bundle();
bundle.putString("Title",getTitle);
bundle.putString("id",mAuth.getCurrentUser().getUid());
obj.setArguments(bundle);
obj.show(getSupportFragmentManager(),"discussionOptionsBottomSheet");
}
});
adapter = new chatAdapter(chatList,getTitle);
Query first = mFirestore.collection("Ideas").document(getTitle).collection("Discussions").orderBy("Time");
first.addSnapshotListener(DiscussionActivity.this, new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if(!documentSnapshots.isEmpty())
{
for(DocumentChange doc:documentSnapshots.getDocumentChanges())
{
if(doc.getType()==DocumentChange.Type.ADDED)
{
chatModel obj = doc.getDocument().toObject(chatModel.class);
chatList.add(obj);
DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
.get(documentSnapshots.size() -1);
Query next = mFirestore.collection("Ideas").document(getTitle).collection("Discussions")
.orderBy("Time").startAfter(lastVisible);
adapter.notifyDataSetChanged();
}
if(doc.getType()==DocumentChange.Type.MODIFIED)
{
String docID = doc.getDocument().getId();
chatModel obj = doc.getDocument().toObject(chatModel.class);
if(doc.getOldIndex() == doc.getNewIndex())
{
chatList.set(doc.getOldIndex(),obj);
}
else
{
chatList.remove(doc.getOldIndex());
chatList.add(doc.getNewIndex(),obj);
adapter.notifyItemMoved(doc.getOldIndex(),doc.getNewIndex());
}
adapter.notifyDataSetChanged();
}
}
}
}
});
LinearLayoutManager layoutManager = new LinearLayoutManager(DiscussionActivity.this);
layoutManager.setReverseLayout(false);
layoutManager.setStackFromEnd(false);
mChatContainer.setHasFixedSize(false);
mChatContainer.setLayoutManager(layoutManager);
mChatContainer.setAdapter(adapter);
}
}
This is the activity_discussion.xml file :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DiscussionActivity"
android:background="#6D7993">
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_above="#id/writingSection"
android:id="#+id/chatContainer"
android:layout_marginRight="5dp">
</android.support.v7.widget.RecyclerView>
<RelativeLayout
android:id="#+id/writingSection"
android:layout_width="379dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="#drawable/chat_background">
<EditText
android:id="#+id/textContent"
android:layout_width="342dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_toLeftOf="#id/include_documents"
android:hint="Write here.." />
<ImageView
android:layout_width="wrap_content"
android:layout_height="28dp"
android:src="#drawable/include_docs"
android:id="#+id/include_documents"
android:layout_toLeftOf="#id/sendMsg"
android:layout_marginTop="9dp"
android:layout_marginRight="3dp"/>
<Button
android:id="#+id/sendMsg"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_marginRight="2dp"
android:layout_marginTop="7dp"
android:background="#drawable/send_message" />
</RelativeLayout>
This is the chatAdapter class :
public class chatAdapter extends
RecyclerView.Adapter<chatAdapter.ViewHolder> {
private FirebaseAuth mAuth;
private FirebaseFirestore mFirestore;
private Context context;
private List<chatModel> chatMsgs;
private String title;
public chatAdapter(List<chatModel> chatMsgs,String title) {
this.chatMsgs = chatMsgs;
this.title = title;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int
viewType) {
mAuth = FirebaseAuth.getInstance();
mFirestore = FirebaseFirestore.getInstance();
context = parent.getContext();
View view =
LayoutInflater.from(context).inflate(R.layout.chat_box_layout,null);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final
int position) {
String getSenderId = chatMsgs.get(position).getSender();
final String getSenderMessage =
chatMsgs.get(position).getMessage();
final String getID = chatMsgs.get(position).getId();
final String theType = chatMsgs.get(position).getType();
if(theType.equals("text"))
{
if(getSenderId.equals(mAuth.getCurrentUser().getUid()))
{
holder.aBox.setVisibility(View.GONE);
holder.oIbox.setVisibility(View.GONE);
holder.mIbox.setVisibility(View.GONE);
//To get name...
mFirestore.collection("Users").document(getSenderId).get()
.addOnCompleteListener((Activity) context, new
OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull
Task<DocumentSnapshot> task) {
if(task.isSuccessful())
{
String getFirstName =
task.getResult().getString("Firstname");
String getLastName =
task.getResult().getString("Lastname");
holder.mName.setText(getFirstName.charAt(0)+getFirstName.substring(1).toLo . werCase());
}
}
});
holder.mContent.setText(getSenderMessage);
}
if(!getSenderId.equals(mAuth.getCurrentUser().getUid())) {
holder.mBox.setVisibility(View.GONE);
holder.aEdit.setVisibility(View.GONE);
holder.aDelete.setVisibility(View.GONE);
holder.oIbox.setVisibility(View.GONE);
holder.mIbox.setVisibility(View.GONE);
//To get name...
mFirestore.collection("Users").document(getSenderId).get()
.addOnCompleteListener((Activity) context, new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
String getFirstName = task.getResult().getString("Firstname");
String getLastName = task.getResult().getString("Lastname");
holder.aName.setText(getFirstName.charAt(0) + getFirstName.substring(1).toLowerCase());
}
}
});
holder.aContent.setText(getSenderMessage);
}
}
}
#Override
public int getItemCount() {
return chatMsgs.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
//Variables for my chat lists...
private TextView mName,mContent;
private ImageView mDelete,mEdit;
private RelativeLayout mBox;
//Variable for other person's chat lists....
private TextView aName,aContent;
private ImageView aDelete,aEdit;
private RelativeLayout aBox;
//Variables for my images list..
private RelativeLayout mIbox;
private ImageView myImage,mIDelete;
private TextView myNameInImage;
//Variables for others image list..
private RelativeLayout oIbox;
private ImageView othersImage,oIDelete;
private TextView othersNameInImage;
public ViewHolder(View itemView) {
super(itemView);
//My variable initialization
mName = (TextView)itemView.findViewById(R.id.name);
mContent = (TextView)itemView.findViewById(R.id.chatContent);
mDelete = (ImageView)itemView.findViewById(R.id.delete);
mEdit = (ImageView)itemView.findViewById(R.id.editContent);
mBox = (RelativeLayout)itemView.findViewById(R.id.userChatBox);
//Other people's variables initialization..
aName = (TextView)itemView.findViewById(R.id.othersName);
aContent = (TextView)itemView.findViewById(R.id.othersChatContent);
aDelete = (ImageView)itemView.findViewById(R.id.othersDelete);
aEdit = (ImageView)itemView.findViewById(R.id.othersEditContent);
aBox = (RelativeLayout)itemView.findViewById(R.id.othersChatBox);
}
}
by this
but the only problem i am facing is that whenever i enter a new message...
I assume you mean getting messages when click sendBtn. Considering you code, fetching messages will happen only when OnCreate() raises (When app starts) >> So, it happens only once!
What you have to do is put first.addSnapshotListener() in a separate void and call in OnCreate() as well as sendBtn.setOnClickListener().
I hope I am being clear, and GOOD LUCK!
Apparently i changed my single chat box item layout, like i tried to make the current user chatbox(My message) and the other user chatbox in the same layout and tried to hide it accordingly...As soon as I changed it that is i made two separate layouts :
1. my_chatbox - To show my messages
2. other_chatbox.xml - For others to send a message..
and altered my adapter accordingly....
And it works now, even for the images. :)
here are codes : -
my_chatbox.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/userChatBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_alignParentTop="true">
<RelativeLayout
android:id="#+id/chatBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:background="#drawable/chat_background">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="20dp"
android:text="Name"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:textColor="#000000"
android:textStyle="bold" />
<TextView
android:id="#+id/chatContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/name"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="20dp"
android:text="Content"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:textColor="#000000" />
</RelativeLayout>
<ImageView
android:id="#+id/delete"
android:layout_width="25dp"
android:layout_height="15dp"
android:layout_alignEnd="#+id/chatBox"
android:layout_below="#+id/chatBox"
android:layout_marginTop="-10dp"
android:src="#drawable/delete" />
<ImageView
android:id="#+id/editContent"
android:layout_width="25dp"
android:layout_height="15dp"
android:layout_below="#+id/chatBox"
android:layout_marginTop="-10dp"
android:layout_toStartOf="#+id/delete"
android:src="#drawable/edit"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Small"
/>
</RelativeLayout>
</RelativeLayout>
the other_user_chatbox.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/userChatBox"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/chatBox"
android:layout_marginLeft="5dp"
android:layout_marginBottom="10dp"
android:background="#drawable/chat_background"
android:backgroundTint="#F4DDBB">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/name"
android:text="Name"
android:textColor="#000000"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:textStyle="bold"
android:layout_marginLeft="10dp"
android:layout_marginRight="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/name"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:id="#+id/chatContent"
android:text="Content"
android:textColor="#000000"
android:layout_marginLeft="10dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="10dp"/>
</RelativeLayout>
<ImageView
android:id="#+id/othersDelete"
android:layout_width="25dp"
android:layout_height="15dp"
android:layout_below="#id/chatBox"
android:src="#drawable/delete" />
<ImageView
android:layout_width="25dp"
android:layout_height="15dp"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Small"
android:layout_below="#id/chatBox"
android:layout_toRightOf="#id/othersDelete"
android:src="#drawable/edit"
android:layout_marginRight="3dp"
android:id="#+id/othersEditContent"/>
</RelativeLayout>
</RelativeLayout>
Just try to keep the id's same in both the xml so as to make your viewHolder less complex.
And this is my chatAdapter.class :
public class chatAdapter extends RecyclerView.Adapter<chatAdapter.ViewHolder> {
private FirebaseAuth mAuth;
private FirebaseFirestore mFirestore;
private Context context;
private static final int SENT = 0;
private static final int RECEIVED = 1;
private String userID;
private List<chatModel> chatMsgs;
private String title;
public chatAdapter(List<chatModel> chatMsgs,String title,String userID) {
this.chatMsgs = chatMsgs;
this.title = title;
this.userID = userID;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
mAuth = FirebaseAuth.getInstance();
mFirestore = FirebaseFirestore.getInstance();
context = parent.getContext();
View view = null;
if(viewType == SENT)
{
view =
LayoutInflater.from(context).inflate(R.layout.chat_box_layout,parent,false);
}
if(viewType == RECEIVED)
{
view =
LayoutInflater.from(context).inflate(R.layout.other_user_chat_box,parent,false);
}
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
String getSenderId = chatMsgs.get(position).getSender();
final String getSenderMessage = chatMsgs.get(position).getMessage();
final String getID = chatMsgs.get(position).getId();
final String theType = chatMsgs.get(position).getType();
if(theType.equals("text"))
{
//To get name...
mFirestore.collection("Users").document(getSenderId).get()
.addOnCompleteListener((Activity) context, new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
String getFirstName = task.getResult().getString("Firstname");
String getLastName = task.getResult().getString("Lastname");
holder.mName.setText(getFirstName.charAt(0) + getFirstName.substring(1).toLowerCase());
}
}
});
holder.mContent.setText(getSenderMessage);
}
}
#Override
public int getItemCount() {
return chatMsgs.size();
}
#Override
public int getItemViewType(int position) {
if (chatMsgs.get(position).getSender() . equals(userID))
return SENT;
else
return RECEIVED;
}
public class ViewHolder extends RecyclerView.ViewHolder{
//Variables for my chat lists...
private TextView mName,mContent;
private ImageView mDelete,mEdit;
private RelativeLayout mBox;
public ViewHolder(View itemView) {
super(itemView);
//variable initialization
mName = (TextView)itemView.findViewById(R.id.name);
mContent = (TextView)itemView.findViewById(R.id.chatContent);
mDelete = (ImageView)itemView.findViewById(R.id.delete);
mEdit = (ImageView)itemView.findViewById(R.id.editContent);
mBox = (RelativeLayout)itemView.findViewById(R.id.userChatBox);
}
}
}
Hope it helps anyone else with the same problems and others too if they are interested.. :)

Linearlayout manager + recyclerview: StackFromEnd(true) still showing at top instead of bottom

I am new to programming in androidstudio/java so I'm looking for some assistance. I'm currently trying to make an app that is similar to facebook messenger by using firebase and android studio. I'm at the stage where I am trying to create the layout for the ChatActivity (see code below). However, I'm having some issues with showing new messages at the bottom of the screen.
I have tried using ".setStackFromEnd(true);" but setting it either true or false, the text still appears at the top! (see images)
Code:
ChatActivity is as follows:
public class ChatActivity extends AppCompatActivity {
//Firebase variables
private FirebaseAuth mAuth;
private DatabaseReference mDatabaseUser, mDatabaseChat;
private FirebaseStorage mStorage;
private StorageReference mStorageReference;
//Recyclerview variables
private RecyclerView recyclerView;
private RecyclerViewChatAdapter mChatAdapter;
//Variables for users
private String userId,friendId,namefriend,chatId;
private CircleImageView mImageFriend;
private ArrayList<ChatObject> resultsChat = new ArrayList<>();
private Button mSendButton;
private EditText mSendText;
private TextView mNameFriend;
//Linear layout manager
private LinearLayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
//prevent opening keyboard automatically
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
//Set firebase variables
mAuth = FirebaseAuth.getInstance();
userId = mAuth.getCurrentUser().getUid();
friendId = getIntent().getExtras().getString("friendId");
namefriend = getIntent().getExtras().getString("friendName");
mDatabaseUser = FirebaseDatabase.getInstance().getReference().child("Friends").child(userId).child("Friendlist").child(friendId).child("chatId");
mDatabaseChat = FirebaseDatabase.getInstance().getReference();
mStorage = FirebaseStorage.getInstance();
mStorageReference = mStorage.getReference();
//Get findviewbyId's
recyclerView = (RecyclerView) findViewById(R.id.ChatActivity_recyclerview);
mSendButton = (Button) findViewById(R.id.ChatActivity_Send);
mSendText = (EditText) findViewById(R.id.ChatActivity_SendText);
mNameFriend = (TextView) findViewById(R.id.ChatActivity_Name);
mImageFriend = (CircleImageView) findViewById(R.id.ChatActivity_ImageFriend);
//Filling in recyclerview and adapter
FillInRecyclerView();
//Set name
mNameFriend.setText(" "+namefriend);
//set picture
StorageReference profileRef = mStorageReference.child("profilepictures/"+friendId);
GlideApp.with(this)
.load(profileRef)
.into(mImageFriend);
//Setting database for messages
getChatId();
//Send message
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendMessage();
}
});
}
private void sendMessage() {
String sendMessageText = mSendText.getText().toString();
if(!sendMessageText.isEmpty()){
DatabaseReference newMessageDb = mDatabaseChat.push();
Map newMessage = new HashMap();
newMessage.put("createdByUser", userId);
newMessage.put("text", sendMessageText);
newMessageDb.setValue(newMessage);
}
mSendText.setText(null);
}
private void getChatId(){
mDatabaseUser.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
chatId = dataSnapshot.getValue().toString();
mDatabaseChat = mDatabaseChat.child("Message").child(chatId);
getChatMessages();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void getChatMessages() {
mDatabaseChat.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
if(dataSnapshot.exists()){
String message = null;
String createdByUser = null;
if (dataSnapshot.child("text").getValue()!=null){
message = dataSnapshot.child("text").getValue().toString();
}
if (dataSnapshot.child("createdByUser").getValue()!=null){
createdByUser = dataSnapshot.child("createdByUser").getValue().toString();
}
if(message!=null && createdByUser!=null){
Boolean currentUserBoolean = false;
if(createdByUser.equals(userId)){
currentUserBoolean=true;
}
ChatObject newMessage = new ChatObject(message, currentUserBoolean, createdByUser);
resultsChat.add(0,newMessage);
mChatAdapter.notifyDataSetChanged();
mLayoutManager.scrollToPositionWithOffset(0,0);
}
}
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
public void FillInRecyclerView(){
mLayoutManager = new LinearLayoutManager(this);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(true);
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
mLayoutManager.scrollToPositionWithOffset(0,0);
mChatAdapter = new RecyclerViewChatAdapter(ChatActivity.this, resultsChat);
recyclerView.setAdapter(mChatAdapter);
recyclerView.setLayoutManager(mLayoutManager);
}
ActivityChat XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ChatActivity">
<LinearLayout
android:id="#+id/ChatActivity_LinearLayoutHeader"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#drawable/background_chatheader"
android:paddingStart="7dp"
android:paddingLeft="7dp"
android:windowSoftInputMode="adjustResize"
android:layout_marginBottom="3dp">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="45dp"
android:layout_height="45dp"
android:id="#+id/ChatActivity_ImageFriend"
android:src="#mipmap/ic_launcher"
android:layout_gravity="center"
/>
<TextView
android:id="#+id/ChatActivity_Name"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="Test"
android:gravity="center_vertical|start"
android:textSize="25sp"
android:textColor="#color/white"
android:fontFamily="sans-serif"
/>
</LinearLayout>
<android.support.v4.widget.NestedScrollView
android:layout_below="#+id/ChatActivity_LinearLayoutHeader"
android:layout_above="#id/ChatActivity_LinearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:scrollbarStyle="outsideOverlay"
>
<android.support.v7.widget.RecyclerView
app:stackFromEnd="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/ChatActivity_LinearLayout"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
android:id="#+id/ChatActivity_recyclerview"
>
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="#+id/ChatActivity_LinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<EditText
android:layout_weight="0.7"
android:id="#+id/ChatActivity_SendText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Type your message..."
/>
<Button
android:layout_weight="0.3"
android:id="#+id/ChatActivity_Send"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="send"/>
</LinearLayout>
</RelativeLayout>
Itemlayout xml file for the recyclerview:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/Recyclerview_Parent_Container"
>
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/Recyclerview_ChatImage"
android:layout_width="42dp"
android:layout_height="42dp"
android:src="#mipmap/ic_launcher"
android:visibility="invisible"
/>
<LinearLayout
android:layout_marginStart="9dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6sp"
android:id="#+id/Recyclerview_Container"
android:orientation="horizontal"
android:background="#drawable/border_chat_bubbles"
android:layout_marginLeft="7dp"
android:layout_marginEnd="7dp">
<TextView
android:id="#+id/Recyclerview_Message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Text"
android:textSize="18sp"
/>
</LinearLayout>
</LinearLayout>
RecyclerView adapter code:
public class RecyclerViewChatAdapter extends RecyclerView.Adapter<RecyclerViewChatAdapter.ViewHolder> {
private List<ChatObject> chatList;
private Context context;
//Firebase
private FirebaseAuth mAuth;
private String CurrentUserId;
private FirebaseStorage mStorage;
private StorageReference mStorageReference;
public RecyclerViewChatAdapter(Context context, List<ChatObject> chatList) {
this.chatList = chatList;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_chatlist_layout, viewGroup, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
//Firebase variables
mStorage = FirebaseStorage.getInstance();
mStorageReference = mStorage.getReference();
mAuth = FirebaseAuth.getInstance();
CurrentUserId = mAuth.getCurrentUser().getUid();
//Setting profile picture into recyclerview
StorageReference profileRef = mStorageReference.child("profilepictures/" + chatList.get(position).getUserid());
GlideApp.with(context)
.load(profileRef)
.into(holder.mProfilepicture);
//Setting message layout for user and friend
holder.mMessage.setText(chatList.get(position).getMessage());
if (chatList.get(position).getCurrentUser()) {
holder.mParentContainer.setGravity(Gravity.END);
holder.mMessage.setTextColor(Color.parseColor("#404040"));
holder.mContainer.setBackgroundResource(R.drawable.border_chat_bubbles);
holder.mProfilepicture.setVisibility(View.INVISIBLE);
} else {
holder.mParentContainer.setGravity(Gravity.START);
holder.mMessage.setTextColor(Color.parseColor("#FFFFFF"));
holder.mContainer.setBackgroundResource(R.drawable.border_chat_bubbles_friend);
holder.mProfilepicture.setVisibility(View.VISIBLE);
//Set picture of friend when multiple messages
int i = 1;
if(position+i<chatList.size()) {
while (!chatList.get(position + i).getCurrentUser()) {
if ((chatList.get(position + i).getCurrentUser()) == chatList.get(position).getCurrentUser()) {
holder.mProfilepicture.setVisibility(View.INVISIBLE);
i++;
} else {
break;
}
if (position + i == chatList.size()) {
break;
}
}
}
}
}
#Override
public int getItemCount() {
return this.chatList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView mMessage;
LinearLayout mContainer, mParentContainer;
CircleImageView mProfilepicture;
public ViewHolder(View itemView) {
super(itemView);
mParentContainer = itemView.findViewById(R.id.Recyclerview_Parent_Container);
mMessage = itemView.findViewById(R.id.Recyclerview_Message);
mContainer = itemView.findViewById(R.id.Recyclerview_Container);
mProfilepicture = itemView.findViewById(R.id.Recyclerview_ChatImage);
}
}
What it looks like on the emulator:
Screenshot of emulator of what it looks like
What I want it to look like:
Emulator of what I want
Now if I set SetStackFromEnd to true or false, I keep getting the same result as in the above picture. However, SetReverseLayout does work! What also does not work is the scrollToPositionWithOffset(0,0); or any other variation, I think the issue must be linked to each other
What have I tried to do already and did not work:
changing the position at what time "FillInRecyclerView()" method is being called, however this did not change anything.
Various combinations of SetReverseLayout/SetStackFromEnd to true
Setting stackfromend to true in the XML code
Changing the RelativeLayout to a LinearLayout in 'ChatActivity.xml'
Setting the relative layout height to match parent
Any help is welcome!
Thank you
You need to use both setStackFromEnd and setReverseLayout. Set both value true and you will get your expected output.
LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(mContext);
recyclerView.setLayoutManager(mLinearLayoutManager);
mLinearLayoutManager.setStackFromEnd(true);
mLinearLayoutManager.setReverseLayout(true);

Unable to populate RecyclerView adapter with Firebase data

I'm trying to fetch the data from my Firebase database but from some reason it doesn't work, so I'll try to provide as much info as posible ..
This is the database snapshot:
This is a POJO class:
public class Result2 implements Serializable {
private int score;
private String userName;
public Result2(int score, String userName) {
this.score = score;
this.userName = userName;
}
public int getScore() {
return score;
}
public String getUserName() {
return userName;
}
}
This is my activitys layout called activity_results.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:weightSum="2"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:textColor="#000"
android:textSize="16sp"
android:gravity="center"
android:text="USERNAME"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<TextView
android:textColor="#000"
android:textSize="16sp"
android:text="SCORE"
android:gravity="center"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
<View
android:background="#000"
android:layout_width="match_parent"
android:layout_height="1dp"
/>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp"
android:clipToPadding="false"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
As you can see, I want to have 2 TextViews that will act like tabs and a RecyclerView underneath that will show the data
Here is my Adapters ViewHolder layout called score_view_holder.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:weightSum="2">
<TextView
android:id="#+id/username"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textSize="14sp" />
<TextView
android:id="#+id/score"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textSize="14sp" />
</LinearLayout>
<View
android:background="#4545"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"/>
So it will contain two horizontal TextViews and a View as a line below..
Here is my Adapter:
public class ScoreAdapter extends RecyclerView.Adapter<ScoreAdapter.ScoreViewHolder> {
private List<Result2> results = new ArrayList<>();
public void setResults(List<Result2> results) {
this.results.clear();
this.results.addAll(results);
notifyDataSetChanged();
}
#Override
public ScoreAdapter.ScoreViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.score_view_holder, parent, false);
return new ScoreAdapter.ScoreViewHolder(view);
}
#Override
public void onBindViewHolder(ScoreAdapter.ScoreViewHolder holder, int position) {
Result2 result = getResult(position);
if (result != null) {
holder.setUsername(result.getUserName() != null ? result.getUserName() : "-");
holder.setScore(String.valueOf(result.getScore()));
}
}
private Result2 getResult(int position) {
return !results.isEmpty() ? results.get(position) : null;
}
#Override
public int getItemCount() {
return results.size();
}
public class ScoreViewHolder extends RecyclerView.ViewHolder {
private TextView username;
private TextView score;
public ScoreViewHolder(View itemView) {
super(itemView);
username = itemView.findViewById(R.id.username);
score = itemView.findViewById(R.id.score);
}
public void setUsername(String username) {
this.username.setText(username);
}
public void setScore(String score) {
this.score.setText(score);
}
}
}
It should get List of Result2 objects and just set text in those two TextViews (username and score)
And finally my Activity where all the magic doesn't happen :)
public class Results extends AppCompatActivity {
private DatabaseReference mDatabase;
private ScoreAdapter scoreAdapter;
private RecyclerView recyclerView;
private List<Result2> results = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_results);
recyclerView = findViewById(R.id.recycler_view);
scoreAdapter = new ScoreAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(scoreAdapter);
mDatabase = FirebaseDatabase.getInstance().getReference();
loadResults();
}
private void loadResults() {
mDatabase.child("Users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot : dataSnapshot.getChildren()) {
Result2 result = childSnapshot.getValue(Result2.class);
if(result != null) {
results.add(result);
}
}
Toast.makeText(Results.this, String.valueOf(results.size()), Toast.LENGTH_SHORT).show();
scoreAdapter.setResults(results);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
}
);
}
}
Funniest thing, Toast shows correct number of Results, but when scoreAdapter.setResults(results); is called, screen blinks and goes back to first screen... Does it have something to do with a POJO class, or onDataChange method or main thread?
I tried with debugging and also funny thing here.. This is what is caught on breakpoint inside ScoreAdapter setResult method:
I tried setting breakpoints inside onBindViewHolder and getResults() but none of them gets called :o
if(result != null) {
results.add(result);
}
See here you are checking result != null. But result is a reference variable of type Results. So it will not be null, it will contains some value.
So, try removing that if statement and do only -
results.add(result);

Recycler View with firebase just displaying the first instance

Hi I ma trying to build an app that has a list of events retrieved from a firebase database but when I run it it displays just the first event stored.
there is the code I used to generate the list:
private RecyclerView recyclerView;
private FirebaseRecyclerAdapter<Event,EventViewHolder> firebaseRecyclerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calendario);
recyclerView = (RecyclerView) findViewById(R.id.eventiList);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Query query = FirebaseDatabase.getInstance().getReference("Eventi");
FirebaseRecyclerOptions<Event> options =
new FirebaseRecyclerOptions.Builder<Event>().setQuery(query, Event.class).build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Event, EventViewHolder>(options) {
#NonNull
#Override
public EventViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.event_layout, parent, false);
return new EventViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull EventViewHolder holder, final int position, #NonNull Event model) {
holder.setDay(model.getData().substring(0,2));
holder.setMonth(model.getMese());
holder.setName(model.getNome());
holder.setLuogo(model.getLuogo());
holder.setendStart(model.getOra_inizio()+ " - "+ model.getOra_fine());
holder.mview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
};
recyclerView.setAdapter(firebaseRecyclerAdapter);
}
public static class EventViewHolder extends RecyclerView.ViewHolder
{
View mview;
public EventViewHolder(View itemView)
{
super(itemView);
mview=itemView;
}
public void setDay(String day)
{
TextView mtext= (TextView)mview.findViewById(R.id.day);
mtext.setText(day);
}
public void setName(String name)
{
TextView maut=(TextView)mview.findViewById(R.id.Event_Name);
maut.setText(name);
}
public void setMonth(String month)
{
TextView maut=(TextView)mview.findViewById(R.id.month);
maut.setText(month);
}
public void setLuogo(String luogo)
{
TextView maut=(TextView)mview.findViewById(R.id.luogo);
maut.setText(luogo);
}
public void setendStart(String endStart)
{
TextView maut=(TextView)mview.findViewById(R.id.start_end);
maut.setText(endStart);
}
}
#Override
protected void onStart() {
super.onStart();
firebaseRecyclerAdapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
//mAdapter.stopListening();
firebaseRecyclerAdapter.stopListening();
}
this is the code of the model class
public class Event {
private String Nome;
private String data;
private String descrizione;
private String luogo;
private String mese;
private String ora_fine;
private String ora_inizio;
private String type;
public Event()
{
}
public Event(String nome, String data, String descrizione, String luogo, String mese, String ora_fine, String ora_inizio, String type) {
Nome = nome;
this.data = data;
this.descrizione = descrizione;
this.luogo = luogo;
this.mese = mese;
this.ora_fine = ora_fine;
this.ora_inizio = ora_inizio;
this.type = type;
}
public String getNome() {
return Nome;
}
public String getData() {
return data;
}
public String getDescrizione() {
return descrizione;
}
public String getLuogo() {
return luogo;
}
public String getMese() {
return mese;
}
public String getOra_fine() {
return ora_fine;
}
public String getOra_inizio() {
return ora_inizio;
}
public String getType() {
return type;
}
}
this is the Calendar activity layout
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Calendario"
android:id="#+id/Calendar_draw">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/eventiList"></android.support.v7.widget.RecyclerView>
</android.support.v4.widget.DrawerLayout>
This is the code for the recycler view row
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="119dp"
android:background="#color/darkBlue">
<TextView
android:id="#+id/day"
android:layout_width="86dp"
android:layout_height="66dp"
android:layout_alignParentStart="true"
android:layout_alignTop="#+id/Event_Name"
android:layout_marginStart="18dp"
android:textColor="#color/white"
android:textSize="50dp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="18dp" />
<TextView
android:id="#+id/month"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignStart="#+id/day"
android:layout_marginBottom="11dp"
android:textColor="#color/white"
android:textStyle="bold"
android:layout_alignLeft="#+id/day" />
<TextView
android:id="#+id/Event_Name"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="124dp"
android:layout_marginTop="13dp"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:textColor="#color/white"
android:textStyle="bold"
android:layout_alignParentLeft="true"
android:layout_marginLeft="124dp" />
<TextView
android:id="#+id/start_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginStart="135dp"
android:textAppearance="#style/TextAppearance.AppCompat.Small"
android:textColor="#color/white"
android:textStyle="italic" />
<TextView
android:id="#+id/luogo"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_alignStart="#+id/start_end"
android:layout_below="#+id/day"
android:textAppearance="#style/TextAppearance.AppCompat.Small"
android:textColor="#color/white"
android:textStyle="italic" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
As you can see from the image that follows it displays just one event and I have 5 in the database
Display
The code worked fine for other lists that are in the app I don't understand why it is not working for this one hope I can get an answer here, thanks
Edit: this is the Database tree
Database Tree
Problem Solved, the layout_height parameter was set to match_parent in the event_layout LinearLayout and CardView. I set it to wrap_content on both and it worked.

Categories

Resources