#android #kotlin #nullpointerexception #layout-inflater
#Android #kotlin #исключение nullpointerexception #макет-надуватель
Вопрос:
Я застрял на этой проблеме на некоторое время, и я просмотрел другие вопросы по этому вопросу. Однако я не до конца понимаю их решения и как это можно применить к моему случаю.
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)
Активность в чате
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 amp;amp; grantResults[0]==PackageManager.PERMISSION_GRANTED){
if(bottomSheetDialog!=null){
bottomSheetDialog.show()
}
}else{
Toast.makeText(this, "Permission needed", Toast.LENGTH_SHORT).show()
}
}
}
}
Если бы кто-нибудь мог объяснить (простым способом), как можно подойти к этим типам проблем и решить их, и как это решить в моем случае, это было бы с благодарностью!
Ответ №1:
LayoutInflater еще не создан. При выполнении чего-либо с views вам в значительной степени приходится ждать, пока onCreate
метод. Итак, что-то вроде этого:
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)
......
}