I have been stuck on this issue for a bit of time now and I have looked through other questions on the subject. However, I do not fully understand their solutions and how it could be applied to my case.
Logcat
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.realtimechat/com.example.realtimechat.chats.ChatActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.LayoutInflater android.view.Window.getLayoutInflater()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3022)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3259)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1950)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7073)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.LayoutInflater android.view.Window.getLayoutInflater()' on a null object reference
at android.app.Activity.getLayoutInflater(Activity.java:4435)
at com.example.realtimechat.chats.ChatActivity.<init>(ChatActivity.kt:66)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3010)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3259)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1950)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7073)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Chat Activity
package com.example.realtimechat.chats
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_PICK
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.provider.MediaStore.ACTION_IMAGE_CAPTURE
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.example.realtimechat.R
import com.example.realtimechat.common.Constants
import com.example.realtimechat.common.Extras
import com.example.realtimechat.common.NodeNames
import com.example.realtimechat.common.Utils
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.google.firebase.storage.FirebaseStorage
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
class ChatActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var etMessage: EditText
private lateinit var ivSend: ImageView
private lateinit var ivAttachment: ImageView
private lateinit var mAuth: FirebaseAuth
private lateinit var mRootRef: DatabaseReference
private lateinit var currentUserId: String
private lateinit var chatUserId: String
private lateinit var rvMessages: RecyclerView
private lateinit var srlMessages: SwipeRefreshLayout
private lateinit var messagesAdapter: MessagesAdapter
private lateinit var messagesList: MutableList<MessageModel>
private var currentPage = 1
companion object {
private const val RECORD_PER_PAGE = 30
}
private val REQUEST_CODE_CAPTURE_IMAGE=102
private val REQUEST_CODE_PICK_IMAGE=101
private val REQUEST_CODE_PICK_VIDEO=103
private lateinit var databaseReferenceMessages: DatabaseReference
private lateinit var childEventListener: ChildEventListener
private lateinit var bottomSheetDialog: BottomSheetDialog
val view: View = layoutInflater.inflate(R.layout.chat_file_options, null)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
etMessage = findViewById(R.id.etMessage)
ivSend = findViewById(R.id.ivSend)
ivAttachment = findViewById(R.id.ivAttachment)
ivSend.setOnClickListener(this)
ivAttachment.setOnClickListener(this)
mAuth = FirebaseAuth.getInstance()
mRootRef = FirebaseDatabase.getInstance().reference
currentUserId = mAuth.currentUser!!.uid
if(intent.hasExtra(Extras.USER_KEY)){
chatUserId = intent.getStringExtra(Extras.USER_KEY)!!
}
rvMessages = findViewById(R.id.rvMessages)
srlMessages = findViewById(R.id.srlMessages)
val layoutManager = LinearLayoutManager(applicationContext)
layoutManager.orientation = RecyclerView.VERTICAL
rvMessages.layoutManager = layoutManager
rvMessages.setHasFixedSize(true)
messagesList = ArrayList()
messagesAdapter = MessagesAdapter(this, messagesList)
rvMessages.adapter = messagesAdapter
loadMessages()
rvMessages.scrollToPosition(messagesList.size-1)
srlMessages.setOnRefreshListener(object: SwipeRefreshLayout.OnRefreshListener{
override fun onRefresh() {
currentPage++
loadMessages()
}
})
bottomSheetDialog = BottomSheetDialog(this)
view.findViewById<View>(R.id.llCamera).setOnClickListener(this)
view.findViewById<View>(R.id.llGallery).setOnClickListener(this)
view.findViewById<View>(R.id.llVideo).setOnClickListener(this)
view.findViewById<View>(R.id.ivClose).setOnClickListener(this)
bottomSheetDialog.setContentView(view)
}
//send messages
private fun sendMessage(msg: String, msgType: String, pushId: String){
try {
if (msg != "") {
val messageMap = HashMap<Any, Any>()
messageMap[NodeNames.MESSAGE_ID] = pushId
messageMap[NodeNames.MESSAGE] = msg
messageMap[NodeNames.MESSAGE_TYPE] = msgType
messageMap[NodeNames.MESSAGE_FROM] = currentUserId
messageMap[NodeNames.MESSAGE_TIME] = ServerValue.TIMESTAMP
val currentUserRef = NodeNames.MESSAGES + "/" + currentUserId + "/" + chatUserId
val chatUserRef = NodeNames.MESSAGES + "/" + chatUserId + "/" + currentUserId
val messageUserMap = mutableMapOf<String, Any>()
messageUserMap["$currentUserRef/$pushId"] = messageMap
messageUserMap["$chatUserRef/$pushId"] = messageMap
etMessage.setText("")
mRootRef.updateChildren(messageUserMap, object : DatabaseReference.CompletionListener {
override fun onComplete(databaseError: DatabaseError?, databaseReference: DatabaseReference) {
if (databaseError != null) {
Toast.makeText(applicationContext, "Failed to send message: ${databaseError.message}", Toast.LENGTH_SHORT).show()
}
run{
Toast.makeText(applicationContext, "Message sent successfully!", Toast.LENGTH_SHORT).show()
}
}
})
}
} catch (e: Exception) {
Toast.makeText(applicationContext, "Failed to send message: ${e.localizedMessage}", Toast.LENGTH_SHORT).show()
}
}
private fun loadMessages(){
messagesList.clear()
databaseReferenceMessages = mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId)
val messageQuery: Query = databaseReferenceMessages.limitToLast(currentPage * RECORD_PER_PAGE)
childEventListener = object: ChildEventListener{
override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
val message: MessageModel = snapshot.getValue(MessageModel::class.java)!!
messagesList.add(message)
messagesAdapter.notifyDataSetChanged()
rvMessages.scrollToPosition(messagesList.size-1)
srlMessages.isRefreshing = false
}
override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
}
override fun onCancelled(error: DatabaseError) {
srlMessages.isRefreshing = false
}
}
messageQuery.addChildEventListener(childEventListener)
}
private fun uploadFile(uri: Uri, messageType: String){
val databaseReference = mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId).push()
val pushId = databaseReference.key!!
val folderName =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) Constants.MESSAGE_VIDEOS else Constants.MESSAGE_IMAGES
val fileName: String =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) "$pushId.mp4" else "$pushId.jpg"
val storageReference = FirebaseStorage.getInstance().reference
val fileReference = storageReference.child(folderName).child(fileName)
fileReference.putFile(uri)
}
private fun uploadBytes(bytes: ByteArrayOutputStream, messageType: String){
val databaseReference = mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId).push()
val pushId = databaseReference.key!!
val folderName =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) Constants.MESSAGE_VIDEOS else Constants.MESSAGE_IMAGES
val fileName: String =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) "$pushId.mp4" else "$pushId.jpg"
val storageReference = FirebaseStorage.getInstance().reference
val fileReference = storageReference.child(folderName).child(fileName)
fileReference.putBytes(bytes.toByteArray())
}
//if any objects are clicked
override fun onClick(v: View?) {
when(v!!.id){
R.id.ivSend -> {
val utility = Utils()
if(utility.connectionAvailable(this)) {
val message = etMessage.text.toString().trim()
val messageType = NodeNames.MESSAGE_TYPE_TEXT
val userMessagePush =
mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId)
.push()
val pushId = userMessagePush.key
sendMessage(message, messageType, pushId!!)
}else{
Toast.makeText(applicationContext, "No Internet connection available", Toast.LENGTH_SHORT).show()
}
}
R.id.ivAttachment -> {
if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED){
if(bottomSheetDialog!=null){
bottomSheetDialog.show()
}
}else{
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1)
}
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
if(inputMethodManager!=null){
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
}
R.id.llCamera -> {
bottomSheetDialog.dismiss()
val intentCamera = Intent(ACTION_IMAGE_CAPTURE)
startActivityForResult(intentCamera, REQUEST_CODE_CAPTURE_IMAGE)
}
R.id.llGallery -> {
bottomSheetDialog.dismiss()
val intentImage = Intent(ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intentImage, REQUEST_CODE_PICK_IMAGE)
}
R.id.llVideo -> {
bottomSheetDialog.dismiss()
val intentVideo = Intent(ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intentVideo, REQUEST_CODE_PICK_VIDEO)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode== Activity.RESULT_OK){
if(requestCode==REQUEST_CODE_CAPTURE_IMAGE) {
val bitMap = data!!.extras!!.get("data") as Bitmap
val bytes = ByteArrayOutputStream()
bitMap.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
uploadBytes(bytes, Constants.MESSAGE_TYPE_IMAGE)
}else if(requestCode==REQUEST_CODE_PICK_IMAGE){
val uri = data!!.data!!
uploadFile(uri, Constants.MESSAGE_TYPE_IMAGE)
}else if(requestCode==REQUEST_CODE_PICK_VIDEO){
val uri = data!!.data!!
uploadFile(uri, Constants.MESSAGE_TYPE_VIDEO)
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode==1){
if(grantResults.size>1 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
if(bottomSheetDialog!=null){
bottomSheetDialog.show()
}
}else{
Toast.makeText(this, "Permission needed", Toast.LENGTH_SHORT).show()
}
}
}
}
If anyone could explain (in an easy manner) how these types of problems could be approached and solved and how to solve it in my case, it would be greatly appreciated!
layoutInflater hasn't been instantiated yet. When doing anything with views, you pretty much have to wait until the onCreate
method. So something like this:
var view: View? = null
// OR
lateinit var view: View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
view = layoutInflater.inflate(R.layout.chat_file_options, null)
......
}