I am trying to build a chatting application but whenever I click on the any of the users it crashes.
class MessegeActivity : AppCompatActivity() {
var userIdVisit: String = ""
var currentUserId : FirebaseUser?=null
var chatsAdpater:ChatAdpater?=null
var mChatList:List<Chat>?=null
lateinit var recycler_view_chat:RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_messege)
intent = intent
userIdVisit = intent.getStringExtra("visit_id")
currentUserId =FirebaseAuth.getInstance().currentUser!!
recycler_view_chat =findViewById(R.id.recycler_view_chat)
recycler_view_chat.setHasFixedSize(true)
var linearLayoutManager =LinearLayoutManager(applicationContext)
linearLayoutManager.stackFromEnd =true
recycler_view_chat.layoutManager =linearLayoutManager
//showing other username and profile dp
val reference = FirebaseDatabase.getInstance().reference
.child("Users").child(userIdVisit)
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
val user: Users? = p0.getValue(Users::class.java)
username_mchat.text = user!!.getFullName()
Picasso.get().load(user.getImg()).into(profile_image_mchat)
retreiveMsg(currentUserId!!.uid,userIdVisit,user.getImg())
}
override fun onCancelled(error: DatabaseError) {
}
})
send_messege_btn.setOnClickListener {
val messege = text_messege.text.toString()
if (messege == "") {
Toast.makeText(this#MessegeActivity, "Please write something!!", Toast.LENGTH_SHORT)
.show()
} else {
sendMessegeToUser(currentUserId!!.uid, userIdVisit, messege)
}
text_messege.setText("")
}
attach_image_file.setOnClickListener {
val intent = Intent()
intent.action = Intent.ACTION_GET_CONTENT
intent.type = "image/*"
startActivityForResult(Intent.createChooser(intent, "Pick Image"), 198)
}
}
private fun sendMessegeToUser(senderId: String, receiverId: String?, messege: String) {
val reference = FirebaseDatabase.getInstance().reference
val messegeKey:String = reference.push().key!!
val messegeHashMap = HashMap<String, Any?>()
messegeHashMap["sender"] = senderId
messegeHashMap["messege"] = messege
messegeHashMap["receiver"] = receiverId
messegeHashMap["isseen"] = "false"
messegeHashMap["url"] = ""
messegeHashMap["messegeId"] = messegeKey
reference.child("Chats").child(messegeKey).setValue(messegeHashMap)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val ChatsListRefernce =
FirebaseDatabase.getInstance().reference.child("ChatLists").child(currentUserId!!.uid).child(userIdVisit)
ChatsListRefernce.addListenerForSingleValueEvent(object :ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
if(!p0.exists())
{
ChatsListRefernce.child("id").setValue(userIdVisit)
}
val ChatsListReceiverRefernce =
FirebaseDatabase.getInstance().reference.child("ChatLists").child(userIdVisit).child(currentUserId!!.uid)
ChatsListReceiverRefernce.child("id").setValue(currentUserId!!.uid)
}
override fun onCancelled(error: DatabaseError) {
}
})
//notification
// val reference = FirebaseDatabase.getInstance().reference
// .child("Users").child(currentUserId!!.uid)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 198 && resultCode ==RESULT_OK && data!=null && data.data != null) {
val progressBar = ProgressDialog(this)
progressBar.setMessage("Please wait")
progressBar.show()
val fileUri = data.data
val storageRef = FirebaseStorage.getInstance().reference.child("Chat Images")
val ref = FirebaseDatabase.getInstance().reference
val messegeId = ref.push().key
val filepath = storageRef.child("$messegeId.jpg")
var uploadTask: StorageTask<*>
uploadTask = filepath.putFile(fileUri!!)
uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
if (!task.isSuccessful) {
task.exception?.let {
throw it
}
}
return#Continuation filepath.downloadUrl
}).addOnCompleteListener { task ->
val downloadUrl = task.result
val url = downloadUrl.toString()
val messegeHashMap = HashMap<String,Any?>()
messegeHashMap["sender"] = currentUserId!!.uid
messegeHashMap["messege"] = "sent you an image"
messegeHashMap["receiver"] = userIdVisit
messegeHashMap["isseen"] = "false"
messegeHashMap["url"] = url
messegeHashMap["messegeId"] = messegeId.toString()
ref.child("Chats").child(messegeId!!).setValue(messegeHashMap)
progressBar.dismiss()
}
}
}
private fun retreiveMsg(senderId: String, receiverId: String?, recieverimgUrl: String?) {
mChatList =ArrayList()
val reference =FirebaseDatabase.getInstance().reference.child("Chats")
reference.addValueEventListener(object:ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
(mChatList as ArrayList<Chat>).clear()
for (snapshot in p0.children)
{
val chat= snapshot.getValue(Chat::class.java)
if(chat!!.getReceiver().equals(senderId)&& chat.getSender().equals(receiverId) ||
chat.getReceiver().equals(receiverId)&& chat.getSender().equals(senderId))
{
(mChatList as ArrayList<Chat>).add(chat)
}
chatsAdpater = ChatAdpater(this#MessegeActivity,(mChatList as ArrayList<Chat>),recieverimgUrl!!)
recycler_view_chat.adapter =chatsAdpater
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
package com.insidecoderz.trails2.Model
class Chat {
private var sender:String =""
private var messege:String =""
private var receiver:String =""
private var isseen :Boolean= false
private var url:String =""
private var messegeId:String =""
constructor()
constructor(
sender: String,
messege: String,
receiver: String,
isseen:Boolean,
url: String,
messegeId: String
) {
this.sender = sender
this.messege = messege
this.receiver = receiver
this.isseen = isseen
this.url = url
this.messegeId = messegeId
}
fun getSender(): String?{
return sender
}
fun setSender(sender: String){
this.sender =sender
}
fun getMessege(): String?{
return messege
}
fun setMessege(messege: String){
this.messege =messege
}
fun getReceiver(): String?{
return receiver
}
fun setReceiver(receiver: String){
this.receiver =receiver
}
fun isIsSeen(): Boolean {
return isseen
}
fun setIsSeen(isseen: Boolean){
this.isseen =isseen
}
fun getUrl(): String?{
return url
}
fun setUrl(url: String){
this.url =url
}
fun getMessegeId(): String?{
return messegeId
}
fun setMessegeId(messegeId: String){
this.messegeId =messegeId
}
}
I am facing this issue again and again, whenever I run the application in the application in the emulator it crashes with showing this error.
2020-08-22 23:19:59.920 17005-17005/com.insidecoderz.trails2 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.insidecoderz.trails2, PID: 17005
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.Boolean to type com.insidecoderz.trails2.Model.Chat
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:435)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:231)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:79)
at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
at com.insidecoderz.trails2.MessegeActivity$retreiveMsg$1.onDataChange(MessegeActivity.kt:202)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7134)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)
If you access the id of the user with the following code val reference = FirebaseDatabase.getInstance().reference.child("Users").child(userIdVisit) and then you try to get the data as a model Chat you can not do that, instead try FirebaseDatabase.getInstance().reference.child("Users").This way you'll be able to get your data as model Chat but it won't be the id you want, also if at the node "Users" you have more users then you'll obtain all the users info using the model Chat
If you need the information for the userIdVisit then you can you do the following
snapshot.child("userInfo1").getValue();
snapshot.child("userInfo2").getValue();
This is the sample for java, you should adapt it for kotlin, I'm sorry for not providing the sample in kotlin but I'm not familiar with it
Related
I've recently started programming in Kotlin and cannot seem to add a profile picture to a user when registering it.
According to the code here, I can access to the gallery and retrieve the image information. The picture will appear on screen, but after registering the user the image url will not appear anywhere.
class RegisterUser : AppCompatActivity() {
private val database = FirebaseDatabase.getInstance()
private val auth: FirebaseAuth = FirebaseAuth.getInstance()
private val UserCreation = database.getReference("Usuarios")
private val pickImage = 100
private var imageUri: Uri? = null
lateinit var imageView: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register_user)
Goback.setOnClickListener {
val Gobackou = Intent(this, MainActivity::class.java)
startActivity(Gobackou)
}
RegisterConfirm.setOnClickListener {
val SetUser = SetUser.text.toString()
val SetPass = setPass.text.toString()
val SetEmail = SetEmail.text.toString()
if (SetUser.isEmpty() && SetPass.isEmpty() && SetEmail.isEmpty()) {
Toast.makeText(this, "Faltan Campos", Toast.LENGTH_SHORT).show()
} else {
RegisterUserv2(SetEmail, SetPass, SetUser)
}
}
selectPP.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, pickImage)
}
}
var selectedPhotoUri: Uri? = null
//guardar la foto de perfil
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == pickImage) {
val selectedPhotoUri = data?.data
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, selectedPhotoUri)
val bitmapDrawable = BitmapDrawable(bitmap)
userimg.setBackgroundDrawable(bitmapDrawable)
}
}
private fun RegisterUserv2(email: String, password: String, user: String) {
auth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
uploadimage()
UltrasaveUsuario(Usuarios(auth.currentUser!!.uid, user, password, email))
val Gobackou = Intent(this, MainActivity::class.java)
startActivity(Gobackou)
} else {
Toast.makeText(this, "Registro ERROR", Toast.LENGTH_LONG).show()
}
}
}
private fun UltrasaveUsuario(usuario: Usuarios) {
val mensajeFirebase = UserCreation.push()
usuario.id = mensajeFirebase.key ?: ""
mensajeFirebase.setValue(usuario)
}
private fun uploadimage(imageurl: String){
if (selectedPhotoUri == null) return
val filename = UUID.randomUUID().toString()
val ref = FirebaseStorage.getInstance().getReference("/images/$filename/")
ref.putFile(selectedPhotoUri!!)
.addOnSuccessListener {
ref.downloadUrl.addOnSuccessListener{
}
}
}
}
Since you are using firebase I will show you how to save firebase storage.
private fun uploadImage() {
if (mSelectedImageFileUri != null) {
val sRef: StorageReference = FirebaseStorage.getInstance().reference.child(
"users/ $uid/profile.jpg"
)
sRef.putFile(mSelectedImageFileUri!!)
.addOnSuccessListener { taskSnapshot ->
taskSnapshot.metadata!!.reference!!.downloadUrl
.addOnSuccessListener { url ->
}
}.addOnFailureListener {
//error
}
} else {
}
}
then you will take this picture using the user id to take .
firebase>storage to view the image
getImage
val sRef: StorageReference = FirebaseStorage.getInstance().reference.child(
"users/ $uid/profile.jpg"
)
sRef.downloadUrl.addOnSuccessListener {
Picasso.get().load(it).into(globalprofileImage)
}
Build.gradle
implementation 'com.squareup.picasso:picasso:2.71828'
https://www.youtube.com/watch?v=nNYLQcmB7AU&t=449s&ab_channel=SmallAcademy
This question already has answers here:
getContactsFromFirebase() method return an empty list
(1 answer)
Setting Singleton property value in Firebase Listener
(3 answers)
Why does my function that calls an API or launches a coroutine return an empty or null value?
(4 answers)
Closed 1 year ago.
I receive null snapshot in only this two method
private fun getUserName() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").getReference("Users")
databaseReference.child(uAuth.currentUser?.uid.toString()).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var userList :User
userList = snapshot.getValue(User::class.java)!!
userName=userList?.cid.toString()
Toast.makeText(this#ProductDetail,"Username detected",Toast.LENGTH_LONG).show()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun getProductPic(prodImageURL:String) {
storageReference= FirebaseStorage.getInstance().reference.child(prodImageURL)
val localFile = File.createTempFile("tempImage","jpg")
storageReference.getFile(localFile).addOnSuccessListener {
val bitMap= BitmapFactory.decodeFile(localFile.absolutePath)
viewBinding.picViewProd.setImageBitmap(bitMap)
}
}
class ProductDetail : AppCompatActivity() {
private lateinit var databaseReference: DatabaseReference
private lateinit var uAuth:FirebaseAuth
private lateinit var storageReference: StorageReference
private lateinit var viewBinding:ActivityProductDetailBinding
private lateinit var adapter:commentAdapter
private lateinit var tc:String
private lateinit var commentList:ArrayList<commentContain>
private lateinit var thisProductID:String
private lateinit var dateTage :String
private var userName :String=""
private var tailorUID :String=""
private var tailorName :String=""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityProductDetailBinding.inflate(layoutInflater)
val view = viewBinding.root
setContentView(view)
tc=getIntent().getStringExtra("tc").toString()
thisProductID = getIntent().getStringExtra("prodNo").toString()
uAuth = FirebaseAuth.getInstance()
//Comment adapter and recycler view code
commentList= ArrayList()
getTailorName()
getComment()
adapter= commentAdapter(this,commentList)
viewBinding.commentList.layoutManager=LinearLayoutManager(this)
viewBinding.commentList.adapter=adapter
getTimeTag()
val currentUser = uAuth.currentUser?.uid
val currentUserURL = "Users/$currentUser.jpg"
getProductData()
if(tc=="tailor"){
viewBinding.btnOrderProduct.isVisible=false
}
viewBinding.btnOrderProduct.setOnClickListener {
addOrder()
}
viewBinding.picViewTailor.setOnClickListener {
val intent = Intent(this, TailorProfile::class.java)
intent.putExtra("tc",tc)
intent.putExtra("tuid",tailorUID)
startActivity(intent)
}
viewBinding.sendButton.setOnClickListener{
getUserName()
val comment = viewBinding.messageBox.text.toString()
addComment(thisProductID,userName,comment,dateTage,currentUserURL)
}
}
private fun getUserName() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").getReference("Users")
databaseReference.child(uAuth.currentUser?.uid.toString()).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var userList :User
userList = snapshot.getValue(User::class.java)!!
userName=userList?.cid.toString()
Toast.makeText(this#ProductDetail,"Username detected",Toast.LENGTH_LONG).show()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun getProductData() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").reference
databaseReference.child("Product").child(thisProductID).addValueEventListener(object: ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val productData = snapshot.getValue<Product>()
viewBinding.tvViewPrice.setText(productData?.price.toString())
viewBinding.tvViewClothspants.setText(productData?.clothsPants.toString())
viewBinding.tvViewFabric.setText(productData?.fabric.toString())
viewBinding.tvViewHeight.setText(productData?.height.toString())
viewBinding.tvViewHipBust.setText(productData?.hipBust.toString())
viewBinding.tvViewSleeve.setText(productData?.sleeve.toString())
viewBinding.tvViewStyleName.setText(productData?.styleName.toString())
viewBinding.tvViewWaist.setText(productData?.waist.toString())
tailorUID = productData?.tailorID.toString()
getTailorPic(productData?.tailorID.toString())
getProductPic(productData?.imageURL.toString())
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(this#ProductDetail,"Some Things wrong in the database", Toast.LENGTH_SHORT).show()
}
}
)
}
private fun getProductPic(prodImageURL:String) {
storageReference= FirebaseStorage.getInstance().reference.child(prodImageURL)
val localFile = File.createTempFile("tempImage","jpg")
storageReference.getFile(localFile).addOnSuccessListener {
val bitMap= BitmapFactory.decodeFile(localFile.absolutePath)
viewBinding.picViewProd.setImageBitmap(bitMap)
}
}
private fun getTailorName() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").getReference("Users")
databaseReference.child(tailorUID).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val userList = snapshot.getValue(User::class.java)!!
tailorName=userList.cid.toString()
viewBinding.tvPViewTailorName.setText(tailorName)
Toast.makeText(this#ProductDetail,"Username detected",Toast.LENGTH_LONG).show()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun getTailorPic(tailorUID:String){
storageReference= FirebaseStorage.getInstance().reference.child("Users/$tailorUID.jpg")
val localFile = File.createTempFile("tempImage","jpg")
storageReference.getFile(localFile).addOnSuccessListener {
val bitMap= BitmapFactory.decodeFile(localFile.absolutePath)
viewBinding.picViewTailor.setImageBitmap(bitMap)
}
}
private fun getComment() {
databaseReference=FirebaseDatabase.getInstance().getReference()
databaseReference.child("Comment").addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
commentList.clear()
for(postSnapshot in snapshot.children){
val currentComment = postSnapshot.getValue(commentContain::class.java)
if(currentComment?.productID==thisProductID){
commentList.add(currentComment!!)
}
}
adapter.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun addOrder() {
val intent = Intent(this, NewCustomOrder::class.java)
intent.putExtra("tc",tc)
intent.putExtra("prodNo",thisProductID)
startActivity(intent)
}
private fun addComment(productID:String,senderID:String?,comment:String,dateTage:String,currentUserURL:String){
val newComment = commentContain(uAuth.currentUser?.uid,senderID,comment,dateTage,currentUserURL,productID)
databaseReference=FirebaseDatabase.getInstance().reference
databaseReference.child("Comment").child(commentList.size.toString()).setValue(newComment).addOnFailureListener{
Toast.makeText(this,"Some thing wrong for real time database", Toast.LENGTH_SHORT).show()
}.addOnSuccessListener {
Toast.makeText(this,"Comment is added", Toast.LENGTH_SHORT).show()
}
}
private fun getTimeTag() {
val formatter = SimpleDateFormat("yyyy_MM_dd", Locale.getDefault())
val now = Date()
dateTage=formatter.format(now).toString()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
super.onCreateOptionsMenu(menu)
getMenuInflater().inflate(R.menu.all_menu,menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
super.onOptionsItemSelected(item)
if(item.itemId==R.id.toProfile){
val intent = Intent(this, TailorProfile::class.java)
intent.putExtra("tc",tc)
intent.putExtra("tuid",uAuth.currentUser?.uid)
finish()
startActivity(intent)
}
else if(item.itemId == R.id.toHome){
val intent = Intent(this, ProductList::class.java)
intent.putExtra("tc",tc)
finish()
startActivity(intent)
}else if(item.itemId == R.id.logout){
val intent = Intent(this, Ground::class.java)
uAuth.signOut()
finish()
startActivity(intent)
}
return true
}
}
The only problem is the getUserName and getTailorName return null at all,which is cause by the snapshot return a null value. I have tried all the method of get data from firebase realtime database, but all of them meets same problem. The weird thing is only the two function meet that problem. Any one can help me please?
below is the picture output
enter image description here
If you see the read messages function in my activity class below, i wanted to update the isSeen field in firestore, but for some reason it does not work at all. My guess it requires a specific document value but that would not be possible as this a messaging app so there will be a lot of documents created.
Activity Class
class MessageActivity : AppCompatActivity() {
private lateinit var binding: ActivityMessageBinding
private lateinit var chat: ArrayList<Message>
private lateinit var messageAdapter: MessageAdapter
private lateinit var roomID: String
private lateinit var userID: String
private lateinit var recID: String
private var c: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMessageBinding.inflate(layoutInflater)
setContentView(binding.root)
userID = FirebaseAuth.getInstance().uid.toString()
recID = intent.getStringExtra("userID").toString()
val recName:String = intent.getStringExtra("userName").toString()
binding.userName.text = recName
chat = arrayListOf()
messageAdapter = MessageAdapter(chat)
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
when {
userID < recID ->
{
roomID = userID + recID
}
userID.compareTo(recID) == 0 ->
{
Toast.makeText(this, "Error you are chatting with yourself!!!", Toast.LENGTH_SHORT).show()
}
else -> {
roomID = recID + userID
}
}
readMessages(userID,recID)
binding.btnSend.setOnClickListener {
val message: String = binding.textSend.text.toString()
if(message.isNotEmpty()){
sendMessage(userID,recID,message)
binding.textSend.text.clear()
}
else{
Toast.makeText(this,"You can't send empty message", Toast.LENGTH_SHORT).show()
}
}
binding.gps.setOnClickListener {
val uri = "http://maps.google.com/maps?daddr="
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(uri))
intent.setPackage("com.google.android.apps.maps")
startActivity(intent)
}
}
private fun sendMessage(sender: String, rec: String, message: String){
val db = Firebase.firestore
val time: FieldValue = FieldValue.serverTimestamp()
val msg = hashMapOf(
"userID" to sender,
"recID" to rec,
"message" to message,
"time" to time,
"roomID" to roomID,
"isSeen" to false
)
db.collection("chats").document(roomID).collection("messages").document().set(msg,SetOptions.merge())
}
private fun readMessages(userId: String, recId: String){
val rootRef = Firebase.firestore
rootRef.collection("chats").document(roomID).collection("messages").orderBy("time", Query.Direction.ASCENDING).addSnapshotListener(object : EventListener<QuerySnapshot?>
{
override fun onEvent(#Nullable documentSnapshots: QuerySnapshot?, #Nullable e: FirebaseFirestoreException?)
{
if (e != null)
{
Log.e(TAG, "onEvent: Listen failed.", e)
return
}
chat.clear()
if (documentSnapshots != null)
{
for (queryDocumentSnapshots in documentSnapshots)
{
val msg = queryDocumentSnapshots.toObject(Message::class.java)
if (msg.recID == recId && msg.userID == userId || msg.recID == userId && msg.userID == recId)
{
chat.add(msg)
}
if(msg.recID.equals(userID).and(msg.userID.equals(recID))){
rootRef.collection("chats").document(roomID).collection("messages").document().update("isSeen",true)
}
messageAdapter = MessageAdapter(chat)
binding.recyclerView.adapter = messageAdapter
}
}
}
})
}
}
Adapter Class
class MessageAdapter(private val MessageList:ArrayList<Message>):RecyclerView.Adapter<MessageAdapter.MessageViewHolder>() {
private val left = 0
private val right = 1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
return if(viewType==right){
val view1 = LayoutInflater.from(parent.context).inflate(R.layout.chat_sender_item,parent,false)
MessageViewHolder(view1)
}else{
val view2 = LayoutInflater.from(parent.context).inflate(R.layout.chat_receiver_item,parent,false)
MessageViewHolder(view2)
}
}
override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
val message:Message = MessageList[position]
holder.showMessage.text = message.message
if(position==MessageList.size-1){
if(message.isSeen)
{
holder.textSeen.text = "Seen"
}else{
holder.textSeen.text = "Delivered"
}
}else{
holder.textSeen.visibility = View.GONE
}
}
override fun getItemCount(): Int {
return MessageList.size
}
class MessageViewHolder(itemView:View) : RecyclerView.ViewHolder(itemView){
val showMessage: TextView = itemView.findViewById(R.id.showMessage)
val textSeen: TextView = itemView.findViewById(R.id.textSeen)
}
override fun getItemViewType(position: Int): Int {
val userID = FirebaseAuth.getInstance().currentUser!!.uid
return if(MessageList[position].userID==userID)
{
right
}else
{
left
}
}
}
Model Class
package com.aarondcosta99.foodreuseapp.model
data class Message(var userID:String? = "",var message:String? = "",var recID:String? = "",var isSeen:Boolean=false)
Firestore
This won't work:
rootRef.collection("chats").document(roomID).collection("messages").document().update("isSeen",true)
The document() call without any arguments creates a reference to a new non-existing document, which you then try to update. But update() only works when a document already exists, you can't use update() to create a document, so this code ends up doing nothing.
To update a document, you need to specify the complete path to that document. The fact that you need to update a lot of documents makes no difference to that fact, it just means you'll need to paths to a lot of documents.
As far as I can tell, you are trying to update the document that you read in documentSnapshots, which means you already have the DocumentReference handy and can update it with:
queryDocumentSnapshots.reference.update("isSeen",true)
I tried to retrieve data from Firebase using the childeventlistener. I have seen all the methods available on stackoverflow to resolve the difficulty but nothing worked.Code is given below
ViewModel
class AccepyReqViewModel : ViewModel() {
companion object {
const val TAG = "AcceptViewModel"
}
private val _userdetail = MutableLiveData<User>()
val userdetail: LiveData<User>
get() = _userdetail
private val userid = FirebaseAuth.getInstance().currentUser?.uid
private val chatrequest = "CHATREQ"
private val db_chat = FirebaseDatabase.getInstance().getReference(chatrequest)
private val company_info = "User_Info"
private val db_company = FirebaseDatabase.getInstance().getReference(company_info)
private val reqchildeventlister = object : ChildEventListener {
override fun onCancelled(error: DatabaseError) {}
override fun onChildMoved(snapshot: DataSnapshot, p1: String?) {
}
override fun onChildChanged(snapshot: DataSnapshot, p1: String?) {
}
override fun onChildAdded(snapshot: DataSnapshot, p1: String?) {
val getid = snapshot.getValue(Request::class.java)
val id = getid!!.id
val requesttype = getid.requesttype
Log.d(TAG, "Second function to be called")
Log.d(TAG, "$requesttype request type")
id?.let { getDetails(it) }
Log.d(TAG, "$id ID passed")
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
}
fun getRequest() {
Log.d(TAG, "getRequest method called 1st fun")
db_chat.child(userid!!).addChildEventListener(reqchildeventlister)
}
fun getDetails(id: String) {
Log.d(TAG, "Second function called")
db_company.child(id).addChildEventListener(datachildeventlistener)
}
private val datachildeventlistener = object : ChildEventListener {
override fun onCancelled(error: DatabaseError) {
}
override fun onChildMoved(snapshot: DataSnapshot, p1: String?) {
}
override fun onChildChanged(snapshot: DataSnapshot, p1: String?) {
Log.d(TAG, "onChildChanged")
val data = snapshot.getValue(User::class.java)
data?.id = snapshot.key
_userdetail.value = data
}
override fun onChildAdded(snapshot: DataSnapshot, p1: String?) {
val data = snapshot.getValue(User::class.java)
data?.id = snapshot.key
_userdetail.value = data
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
}
}
The Model Class is as follows
import com.google.firebase.database.Exclude
data class User(
#get:Exclude
var id: String? = null,
var isAdmin: Boolean? = true,
var name: String? = null,
var position: String? = null,
var contact: String? = null,
var comname: String? = null,
var address: String? = null,
var email: String? = null,
var website: String? = null
) {
constructor() : this("", true, "", "", "", "", "", "", "")
}
Firebase Realtime Database looks as follows
CHATREQ
8EFvXhAKTfWuIavGhXlz344bgMD2
c2HUyNV6sYQImIFqVNMfIaFDTKT2
id: "c2HUyNV6sYQImIFqVNMfIaFDTKT2"
request_type: "sent"
c2HUyNV6sYQImIFqVNMfIaFDTKT2
8EFvXhAKTfWuIavGhXlz344bgMD2
id: "8EFvXhAKTfWuIavGhXlz344bgMD2"
request_type: "received"
Company_Info
-M6Ez9RiFRpm8_cn35Pp
User_Info
8EFvXhAKTfWuIavGhXlz344bgMD2
admin: false
contact: "484615674"
name: "Chetan"
position: "c"
c2HUyNV6sYQImIFqVNMfIaFDTKT2
address: "add"
admin: true
comname: "Palekar"
contact: "549874561"
email: "add#gmail.com"
name: "Kp"
position: "adfa"
website: "www.add.com"
The stacktrace said that "cant convert object of string to the user Model class"
Hope Someone help me out with this .
Thank-You for your help.
Instead of using childEventListener, you need to use valueEventListener:
private val company_info = "User_Info"
private val db_company = FirebaseDatabase.getInstance().getReference(company_info)
private val reqEventlister = object : ValueEventListener {
override fun onCancelled(error: FirebaseError?) {
println(error!!.message)
}
override fun onDataChange(snapshot: DataSnapshot?) {
val getid = snapshot.getValue(Request::class.java)
val id = getid!!.id
val requesttype = getid.requesttype
Log.d(TAG, "Second function to be called")
Log.d(TAG, "$requesttype request type")
id?.let { getDetails(it) }
Log.d(TAG, "$id ID passed")
}
})
fun getRequest() {
Log.d(TAG, "getRequest method called 1st fun")
db_chat.child(userid!!).addValueEventListener(reqEventlister)
}
When using childEventListener, you are directly retrieving the children under the 8EFvXhAKTfWuIavGhXlz344bgMD2 thus retrieving values of type String. Instead you need to use ValueEventListener which will map your Request class to the data retrieved.
this is the chat functionality on my app but the messages aren't appearing on my app although it is getting updated in the firebase. when I hardcoded the values it is working. this is the conversation activity. I've used a chat fragment and adapter as well. But the messages are just not getting posted on the app. any alternative solutions or a solution for this would be nice.
private val firebaseDB = FirebaseFirestore.getInstance()
private val userId = FirebaseAuth.getInstance().currentUser?.uid
private val conversationAdapter = ConversationAdapter(arrayListOf(), userId)
private var chatId: String? = null
private var imageUrl: String? = null
private var otherUserId: String? = null
private var chatName: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_conversation)
chatId = intent.extras.getString(PARAM_CHAT_ID)
imageUrl = intent.extras.getString(PARAM_IMAGE_URL)
chatName = intent.extras.getString(chatName)
otherUserId = intent.extras.getString(PARAM_OTHER_USER_ID)
if (chatId.isNullOrEmpty() || userId.isNullOrEmpty()) {
Toast.makeText(this, "chat room error", Toast.LENGTH_LONG).show()
finish()
}
topNameTV.text = chatName
populateImage(this, imageUrl, topPhotoIV, R.drawable.default_user)
messagesRV.apply {
setHasFixedSize(false)
layoutManager = LinearLayoutManager(context)
adapter = conversationAdapter
}
firebaseDB.collection(DATA_CHATS)
.document(chatId!!)
.collection(DATA_CHAT_MESSAGES)
.orderBy(DATA_CHAT_MESSAGE_TIME)
.addSnapshotListener{ querySnapshot, firebaseFirestoreException ->
if(firebaseFirestoreException != null){
firebaseFirestoreException.printStackTrace()
return#addSnapshotListener
}else{
if (querySnapshot != null){
for(change in querySnapshot.documentChanges){
when(change.type){
DocumentChange.Type.ADDED -> {
val message = change.document.toObject(Convo::class.java)
if(message != null){
conversationAdapter.addMessage(message)
messagesRV.post {
messagesRV.smoothScrollToPosition(conversationAdapter.itemCount -1)
}
}
}
}
}
}
}
}
}
fun onSend(v: View) {
if (!messageET.text.isNullOrEmpty()){
val message = Convo(userId, messageET.text.toString(), System.currentTimeMillis())
firebaseDB.collection(DATA_CHATS).document(chatId!!)
.collection(DATA_CHAT_MESSAGES)
.document()
.set(message)
messageET.setText("",TextView.BufferType.EDITABLE)
}
}
companion object {
private val PARAM_CHAT_ID = "Chat id"
private val PARAM_IMAGE_URL = "Image url"
private val PARAM_OTHER_USER_ID = "Other user id"
private val PARAM_CHAT_NAME = "Chat name"
fun newIntent(context: Context?, chatId: String?, imageUrl: String?, otherUserId: String?
chatName: String?): Intent{
val intent = Intent(context,ConversationActivity::class.java)
intent.putExtra(PARAM_CHAT_ID,chatId)
intent.putExtra(PARAM_IMAGE_URL, imageUrl)
intent.putExtra(PARAM_OTHER_USER_ID, otherUserId)
intent.putExtra(PARAM_CHAT_NAME, chatName)
return intent
}
}
}