I'm pretty new to programming, so I follow a guide on Youtube that helps to build my chat application. Until now, sending messages via firebase from one user to another works fine, but when I'm trying to enter the conversation that contains new messages, the app crashes. However, once I try to enter the chat after the app crashed, it works fine.
This is the code for the ChatFragment:
package com.example.messengerapp.Fragments
import android.os.Bundle
import android.os.RecoverySystem
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.messengerapp.AdapterClasses.UserAdapter
import com.example.messengerapp.ModelClasses.Chat
import com.example.messengerapp.ModelClasses.Chatlist
import com.example.messengerapp.ModelClasses.Users
import com.example.messengerapp.R
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class ChatFragment : Fragment() {
private var userAdapter: UserAdapter? = null
private var mUsers: List<Users>? = null
private var usersChatList: List<Chatlist>? = null
lateinit var recycler_view_chat_list: RecyclerView
private var firebaseUser: FirebaseUser? = null
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_chat, container, false)
recycler_view_chat_list = view.findViewById(R.id.recycler_view_chat_list)
recycler_view_chat_list.setHasFixedSize(true)
recycler_view_chat_list.layoutManager = LinearLayoutManager(context)
firebaseUser = FirebaseAuth.getInstance().currentUser
usersChatList = ArrayList()
val ref = FirebaseDatabase.getInstance().reference.child("ChatList").child(firebaseUser!!.uid)
ref!!.addValueEventListener(object: ValueEventListener{
override fun onDataChange(p0: DataSnapshot)
{
(usersChatList as ArrayList).clear()
for (dataSnapshot in p0.children)
{
val chatlist = dataSnapshot.getValue(Chatlist::class.java)
(usersChatList as ArrayList).add(chatlist!!)
}
//TODO:: Check why function below crashes
retrieveChatLists()
}
override fun onCancelled(p0: DatabaseError)
{
}
})
return view
}
companion object {
fun newInstance(param1: String, param2: String) =
ChatFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
private fun retrieveChatLists()
{
mUsers = ArrayList()
val ref = FirebaseDatabase.getInstance().reference.child("Users")
ref!!.addValueEventListener(object: ValueEventListener{
override fun onDataChange(p0: DataSnapshot)
{
(mUsers as ArrayList<Users>).clear()
for (dataSnapshot in p0.children)
{
val user= dataSnapshot.getValue(Users::class.java)
for (eachChatList in usersChatList!!)
{
if (user!!.getUID().equals(eachChatList.getId()))
{
(mUsers as ArrayList).add(user!!)
}
}
}
userAdapter = UserAdapter(context!!, (mUsers as ArrayList<Users>), true)
recycler_view_chat_list.adapter = userAdapter
}
override fun onCancelled(p0: DatabaseError)
{
}
})
}
}
This is how I built the UserAdapter:
package com.example.messengerapp.AdapterClasses
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.media.Image
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.messengerapp.MessageChatActivity
import com.example.messengerapp.ModelClasses.Users
import com.example.messengerapp.R
import com.example.messengerapp.WelcomeActivity
import com.squareup.picasso.Picasso
import de.hdodenhof.circleimageview.CircleImageView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.user_search_item_layout.view.*
class UserAdapter(mContext: Context, mUsers: List<Users>, isChatCheck: Boolean) : RecyclerView.Adapter<UserAdapter.ViewHolder?>(){
private val mContext: Context
private val mUsers: List<Users>
private val isChatCheck: Boolean
init {
this.mUsers = mUsers
this.mContext = mContext
this. isChatCheck = isChatCheck
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): UserAdapter.ViewHolder {
val view: View = LayoutInflater.from(mContext).inflate(R.layout.user_search_item_layout, viewGroup, false)
return UserAdapter.ViewHolder(view)
}
override fun onBindViewHolder(holder: UserAdapter.ViewHolder, position: Int) {
val user: Users = mUsers[position]
holder.userNameTxt.text = user!!.getUserName()
Picasso.get().load(user.getProfile()).into(holder.profileImageView)
holder.itemView.setOnClickListener{
val options = arrayOf<CharSequence>("Send Message", "Visit Profile")
val builder: AlertDialog.Builder = AlertDialog.Builder(mContext)
builder.setTitle("What would you like to do?")
builder.setItems(options, DialogInterface.OnClickListener{dialog, which ->
if (which == 0)
{
val intent = Intent(mContext, MessageChatActivity::class.java)
intent.putExtra("visit_id", user.getUID())
mContext.startActivity(intent)
}
if (which == 1)
{
}
})
builder.show()
}
}
override fun getItemCount(): Int {
return mUsers.size
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
var userNameTxt: TextView
var profileImageView: CircleImageView
var onlineImageView: CircleImageView
var offlineImageView: CircleImageView
var lastMessageTxt: TextView
init {
userNameTxt = itemView.findViewById(R.id.username)
profileImageView = itemView.findViewById(R.id.profile_image)
onlineImageView = itemView.findViewById(R.id.image_online)
offlineImageView = itemView.findViewById(R.id.image_offline)
lastMessageTxt = itemView.findViewById(R.id.message_last)
}
}
}
When I'm trying to run the app, as was mentioned, I get the java.lang.NullPointerException exception. When I click on that in the run tab, it brings me to this line in the ChatFragment:
userAdapter = UserAdapter(context!!, (mUsers as ArrayList<Users>), true)
This is the Logcat:
2020-11-03 15:05:46.345 18520-18520/com.example.messengerapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.messengerapp, PID: 18520
java.lang.NullPointerException
at com.example.messengerapp.Fragments.ChatFragment$retrieveChatLists$1.onDataChange(ChatFragment.kt:112)
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:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
I'm not quite sure what the problem is. Hope that I gave the right information. Please help!