简体   繁体   中英

App is force closing after replacing kotlin synthetics with view binding

I was trying to learn new things about android, but as I was changing the project to use viewbinding, the app force closes on launch. It will be a really big help for me to find out what is causing the force close issue.

This is the MainActivity.kt code

class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"

//You can ignore this messageList if you're coming from the tutorial,
// it was used only for my personal debugging
var messagesList = mutableListOf<Message>()

private lateinit var adapter: MessagingAdapter
private val botList = listOf("Peter" , "Peter" , "Peter" , "Peter")
private lateinit var binding: ActivityMainBinding


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    recyclerView()

    clickEvents()

    val random = (0..3).random()
    customBotMessage("Hello! Today you're speaking with ${botList[random]}, how may I help?")
}

private fun clickEvents() {

    //Send a message
    binding.btnSend.setOnClickListener {
        sendMessage()
    }

    //Scroll back to correct position when user clicks on text view
    binding.etMessage.setOnClickListener {
        GlobalScope.launch {
            delay(100)

            withContext(Dispatchers.Main) {
                binding.rvMessages.scrollToPosition(adapter.itemCount - 1)

            }
        }
    }
}

private fun recyclerView() {
    adapter = MessagingAdapter()
    binding.rvMessages.adapter = adapter
    binding.rvMessages.layoutManager = LinearLayoutManager(applicationContext)

}

override fun onStart() {
    super.onStart()
    //In case there are messages, scroll to bottom when re-opening app
    GlobalScope.launch {
        delay(100)
        withContext(Dispatchers.Main) {
            binding.rvMessages.scrollToPosition(adapter.itemCount - 1)
        }
    }
}

private fun sendMessage() {
    val message = binding.etMessage.text.toString()
    val timeStamp = Time.timeStamp()

    if (message.isNotEmpty()) {
        //Adds it to our local list
        messagesList.add(Message(message, SEND_ID, timeStamp))
        binding.etMessage.setText("")

        adapter.insertMessage(Message(message, SEND_ID, timeStamp))
        binding.rvMessages.scrollToPosition(adapter.itemCount - 1)

        botResponse(message)
    }
}

private fun botResponse(message: String) {
    val timeStamp = Time.timeStamp()

    GlobalScope.launch {
        //Fake response delay
        delay(1000)

        withContext(Dispatchers.Main) {
            //Gets the response
            val response = BotResponse.basicResponses(message)

            //Adds it to our local list
            messagesList.add(Message(response, RECEIVE_ID, timeStamp))

            //Inserts our message into the adapter
            adapter.insertMessage(Message(response, RECEIVE_ID, timeStamp))

            //Scrolls us to the position of the latest message
            binding.rvMessages.scrollToPosition(adapter.itemCount - 1)

            //Starts Google
            when (response) {
                OPEN_GOOGLE -> {
                    val site = Intent(Intent.ACTION_VIEW)
                    site.data = Uri.parse("https://www.google.com/")
                    startActivity(site)
                }
                OPEN_SEARCH -> {
                    val site = Intent(Intent.ACTION_VIEW)
                    val searchTerm: String? = message.substringAfterLast("search")
                    site.data = Uri.parse("https://www.google.com/search?&q=$searchTerm")
                    startActivity(site)
                }

            }
        }
    }
}

private fun customBotMessage(message: String) {

    GlobalScope.launch {
        delay(1000)
        withContext(Dispatchers.Main) {
            val timeStamp = Time.timeStamp()
            messagesList.add(Message(message, RECEIVE_ID, timeStamp))
            adapter.insertMessage(Message(message, RECEIVE_ID, timeStamp))

            binding.rvMessages.scrollToPosition(adapter.itemCount - 1)
        }
    }
}

}

This is the MessagingAdapter.kt file

class MessagingAdapter: RecyclerView.Adapter<MessagingAdapter.MessageViewHolder>() {

var messagesList = mutableListOf<Message>()
private lateinit var binding: MessageItemBinding

inner class MessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    init {
        itemView.setOnClickListener {

            //Remove message on the item clicked
            messagesList.removeAt(adapterPosition)
            notifyItemRemoved(adapterPosition)
        }
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {

    return MessageViewHolder(
        LayoutInflater.from(parent.context).inflate(R.layout.message_item, parent, false)
    )
}

override fun getItemCount(): Int {
    return messagesList.size
}

@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
    val currentMessage = messagesList[position]


    when (currentMessage.id) {
        SEND_ID -> {
            holder.itemView.findViewById<View>(R.id.tv_message).apply {
                binding.tvMessage.text = currentMessage.message
                visibility = View.VISIBLE
            }
            holder.itemView.findViewById<View>(R.id.tv_bot_message).visibility = View.GONE
        }
        RECEIVE_ID -> {
            holder.itemView.findViewById<View>(R.id.tv_bot_message).apply {
                binding.tvBotMessage.text = currentMessage.message
                visibility = View.VISIBLE
            }
            holder.itemView.findViewById<View>(R.id.tv_message).visibility = View.GONE
        }
    }
}

fun insertMessage(message: Message) {
    this.messagesList.add(message)
    notifyItemInserted(messagesList.size)
}

}

It would be a really big help if you could help me fix this.

Here is a basic layout of the MessagingAdapter that may work for you. Then within onBindViewHolder you can access your views with holder.binding.viewId . You can adjust it as needed.

class MessagingAdapter(var messagesList: List<Message>) : 
    RecyclerView.Adapter<MessagingAdapter.MessageViewHolder>() {

    inner class MessageViewHolder(val binding: MessageItemBinding) :
        RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
        val view =
            MessageItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return MessageViewHolder(view)
    }
    //other required implementations
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM