I have an app which has a MainActivity, ClientFragment,and ConnectFragment. I want to add a webView to the ClientFragment. However when I try to add it I get an error unresolved reference: findViewById.
I have added to my MainActivity but then the rest of my app doesn't work right.
How and where should I add my WebView?
package com.example.mqttkotlinsample
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.widget.ImageButton
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import org.eclipse.paho.client.mqttv3.*
class ClientFragment : Fragment() {
private lateinit var mqttClient : MQTTClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (mqttClient.isConnected()) {
// Disconnect from MQTT Broker
mqttClient.disconnect(object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken?) {
Log.d(this.javaClass.name, "Disconnected")
Toast.makeText(context, "MQTT Disconnection success", Toast.LENGTH_SHORT).show()
// Disconnection success, come back to Connect Fragment
findNavController().navigate(R.id.action_ClientFragment_to_ConnectFragment)
}
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
Log.d(this.javaClass.name, "Failed to disconnect")
}
})
} else {
Log.d(this.javaClass.name, "Impossible to disconnect, no server connected")
}
}
})
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_client, container, false)
//I have tried this many places but with no luck same error unresolved reference:findViewById.
val webView = findViewById<View>(R.id.webView) as WebView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}}
I have place the WebView in the xml file.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/mainwater"
tools:context=".ConnectFragment">
<WebView
android:id="#+id/webView"
android:layout_width="432dp"
android:layout_height="225dp"
android:layout_marginBottom="224dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView6" />
If anyone can help me get this working I would really appreciate it.
I got it figured out all I had to do was put val webView = view.findViewById<View>(R.id.webView) as WebView
Related
I am trying to make a app that sends messages to a recyclerView from fragment to another using a navgraph, but whenever I go back to my previous fragment to add a new message I lose the data of my recyclerView, and does not pile up.
---This is the kotlin code for the first fragment:
package com.example.passingdata
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import androidx.navigation.Navigation
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class Fragment_A : Fragment() {
// TODO: Rename and change types of parameters
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? {
return inflater.inflate(R.layout.fragment__a, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val messageET = view.findViewById<EditText>(R.id.ETmessageTaker)
val enterBTN = view.findViewById<Button>(R.id.BTNenter)
enterBTN.setOnClickListener{
val action = Fragment_ADirections.actionFragmentAToFragmentB(messageET.text.toString())
Navigation.findNavController(view).navigate(action)
}
}
companion object {
fun newInstance(param1: String, param2: String) =
Fragment_A().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
---XML code for first fragment:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment_A">
<EditText
android:id="#+id/ETmessageTaker"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:ems="10"
android:hint="Message"
android:inputType="textPersonName"
android:minHeight="48dp"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/BTNenter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Enter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/ETmessageTaker" />
</androidx.constraintlayout.widget.ConstraintLayout>
---Kotlin code for second fragment :
package com.example.passingdata
import android.content.ContentValues.TAG
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.passingdata.databinding.FragmentBBinding
import messageAdapter
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
var state: Parcelable? = null
class Fragment_B : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private val args:Fragment_BArgs by navArgs()
private var _binding: FragmentBBinding? = null
private val binding get() = _binding!!
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? {
_binding = FragmentBBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val eachMessage = args.messageRecieved
//putting words in TV
binding.TVNewMessage.text = eachMessage
//putting words in RV
val messageList = mutableListOf(
message(eachMessage)
)
val adapter = messageAdapter(messageList)
binding.RVMessages.adapter = adapter
binding.RVMessages.layoutManager = LinearLayoutManager(context)
binding.BTNBack.setOnClickListener {
Navigation.findNavController(view).navigate(R.id.action_fragment_B_to_fragment_A)
}
}
companion object {
fun newInstance(param1: String, param2: String) =
Fragment_B().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume Called")
state = binding.RVMessages.layoutManager?.onSaveInstanceState();
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause Called")
state = binding.RVMessages.layoutManager?.onSaveInstanceState();
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop Called")
state = binding.RVMessages.layoutManager?.onSaveInstanceState();
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy Called")
_binding = null
}
}
---XML code for second fragment:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment_B">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/RV_messages"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="20dp"
app:layout_constraintBottom_toTopOf="#+id/TV_newMessage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/TV_newMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp"
android:text="TextView"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/BTN_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_marginRight="10dp"
android:text="Back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="#+id/BTN_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="Save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Someone suggested I override the 3 states and save them like this, but it did not work.
I even tried using SharedPrefrences but it gives me a error saying, "Unresolved reference: getSharedPrefrences".
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume Called")
state = binding.RVMessages.layoutManager?.onSaveInstanceState();
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause Called")
state = binding.RVMessages.layoutManager?.onSaveInstanceState();
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop Called")
state = binding.RVMessages.layoutManager?.onSaveInstanceState();
}
I have faced the problem of my application always show keep stopping. It show me the problem is not been initialized. I have try insert findViewbyId for mListener but it say i cannot insert id in constraint layout so mean this way cannot be used. Can somebody help me? Thank for your help
Below are my original code which problem out :
package com.example.assignment_mad
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.imageview.ShapeableImageView
class NotificationAdapter(private val companysList:ArrayList<Company>):RecyclerView.Adapter<NotificationAdapter.MyViewHolder>() {
private lateinit var mListener:onItemClickListener
interface onItemClickListener{
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener: onItemClickListener){
mListener=listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView=LayoutInflater.from(parent.context).inflate(R.layout.list_item,parent,false)
return MyViewHolder(itemView,mListener)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem=companysList[position]
holder.titleImage.setImageResource(currentItem.titleImage)
holder.tvHeading.text=currentItem.heading
}
override fun getItemCount(): Int {
return companysList.size
}
//to insert the post detail
class MyViewHolder(itemView: View,listener: onItemClickListener):RecyclerView.ViewHolder(itemView){
val titleImage:ShapeableImageView=itemView.findViewById(R.id.title_image)
val tvHeading: TextView =itemView.findViewById(R.id.tvHeading)
init {
itemView.setOnClickListener{
listener.onItemClick(adapterPosition)
}
}
}
}
The list_item xml :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="8dp">
<com.google.android.material.imageview.ShapeableImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="#+id/title_image"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="#style/RoundCorner"
android:src="#drawable/company_logo_1"/>
<TextView
android:id="#+id/tvHeading"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:text="Candidate Biden Called Saudi Arable a Pareft eaft."
android:textSize="16dp"
android:textStyle="bold"
android:layout_marginStart="16dp"
android:layout_marginEnd="32dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/title_image"
app:layout_constraintTop_toTopOf="parent"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/title_image"
android:background="#color/underline"/>
</androidx.constraintlayout.widget.ConstraintLayout>
The problem showing :
kotlin.UninitializedPropertyAccessException: lateinit property mListener has not been initialized
at com.example.assignment_mad.NotificationAdapter.onCreateViewHolder(Notificatiion_Adapter.kt:25)
at com.example.assignment_mad.NotificationAdapter.onCreateViewHolder(Notificatiion_Adapter.kt:10)
Add the Nullable check for onItemClickListener type of variable will solve your problem.
package com.example.assignment_mad
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.imageview.ShapeableImageView
class NotificationAdapter(private val companysList:ArrayList<Company>):RecyclerView.Adapter<NotificationAdapter.MyViewHolder>() {
private var mListener:onItemClickListener?=null
interface onItemClickListener{
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener: onItemClickListener){
mListener=listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView=LayoutInflater.from(parent.context).inflate(R.layout.list_item,parent,false)
return MyViewHolder(itemView,mListener)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem=companysList[position]
holder.titleImage.setImageResource(currentItem.titleImage)
holder.tvHeading.text=currentItem.heading
}
override fun getItemCount(): Int {
return companysList.size
}
//to insert the post detail
class MyViewHolder(itemView: View,listener: onItemClickListener?):RecyclerView.ViewHolder(itemView){
val titleImage:ShapeableImageView=itemView.findViewById(R.id.title_image)
val tvHeading: TextView =itemView.findViewById(R.id.tvHeading)
init {
itemView.setOnClickListener{
listener?.onItemClick(adapterPosition)
}
}
}
}
Your problem is you are not initilizing the mListener properly
kotlin.UninitializedPropertyAccessException: lateinit property mListener has not been initialized at com.example.assignment_mad.NotificationAdapter.onCreateViewHolder(Notificatiion_Adapter.kt:25) at com.example.assignment_mad.NotificationAdapter.onCreateViewHolder(Notificatiion_Adapter.kt:10)
My solution is to pass the listener in the adapter constructor
class NotificationAdapter(
private val companysList:ArrayList<Company>,
private val listener:onItemClickListener
){
// delete
private var mListener:onItemClickListener?=null
// and
fun setOnItemClickListener(listener: onItemClickListener){
mListener=listener
}
}
use it in activity/fragment
adapter = NotificationAdapter(list, object: NotificationAdapter.onItemClickListener{
override fun onItemClick(position:Int){
}
})
I have faced the problem that my firebase cannot be worked as well and it just shows me nothing ( white page ) in my application. I need to use firebase to show the material in the recycler view. However, as the new user for firebase, I set my recycler view in string form and after it, I also want to use as one is image one is text. But I think that I need to fix the first problem as well. Can somebody help me? Thank you for your help!!
My original code :
package com.example.assignment_mad
import android.content.ContentValues.TAG
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.example.assignment_mad.databinding.ActivityMainBinding
import com.example.assignment_mad.databinding.FragmentNotificationBinding
import com.example.assignment_mad.databinding.FragmentSearchPageBinding
import com.google.android.material.imageview.ShapeableImageView
import com.google.android.material.tabs.TabLayout
import com.google.firebase.database.*
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import kotlinx.android.synthetic.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_notification_.*
class Notification_Fragment : Fragment( ) {
val database=Firebase.database
val myRef=database.getReference("message")
private var _binding:FragmentNotificationBinding?=null
private val binding get()=_binding!!
private lateinit var dbref: DatabaseReference
private lateinit var newRecyclerView: RecyclerView
private lateinit var newArrayList: ArrayList<Company>
private lateinit var tempArrayList: ArrayList<Company>
lateinit var imageId:Array<Int>
lateinit var heading:Array<String>
lateinit var news:Array<String>
private var layoutManager: RecyclerView.LayoutManager? = null
private var adapter: RecyclerView.Adapter<NotificationAdapter.MyViewHolder>? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var views =inflater.inflate(R.layout.fragment_notification_, container, false)
newRecyclerView=views.findViewById(R.id.recyclerView)
// Inflate the layout for this fragment
return views
}
override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) {
super.onViewCreated(itemView, savedInstanceState)
newArrayList= arrayListOf<Company>()
tempArrayList= arrayListOf<Company>()
getUserdata()
}
private fun getUserdata() {
dbref=FirebaseDatabase.getInstance().getReference("Notification")
dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()){
for (companySnapshot in snapshot.children){
val company=companySnapshot.getValue(Company::class.java)
newArrayList.add(company!!)
}
newRecyclerView.adapter=NotificationAdapter(newArrayList)
}
}
override fun onCancelled(error: DatabaseError) {
Log.w(TAG, "Failed to read value.", error.toException())
}
})
newRecyclerView.layoutManager=LinearLayoutManager(activity)
newRecyclerView.setHasFixedSize(true)
newRecyclerView.adapter=adapter
}
}
The adapter code :
package com.example.assignment_mad
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.imageview.ShapeableImageView
import kotlinx.android.synthetic.main.dropdown_item.view.*
class NotificationAdapter(private val companysList:ArrayList<Company>):RecyclerView.Adapter<NotificationAdapter.MyViewHolder>() {
private var mListener:onItemClickListener?=null
interface onItemClickListener{
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener: onItemClickListener){
mListener=listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView=LayoutInflater.from(parent.context).inflate(R.layout.list_item,parent,false)
return MyViewHolder(itemView,mListener)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem=companysList[position]
holder.titleImage.text=currentItem.titleImage
// holder.titleImage.setImageResource(currentItem.titleImage)
holder.tvHeading.text=currentItem.heading
}
override fun getItemCount(): Int {
return companysList.size
}
//to insert the post detail
class MyViewHolder(itemView: View,listener: onItemClickListener?):RecyclerView.ViewHolder(itemView){
val titleImage:TextView=itemView.findViewById(R.id.title_image)
// val titleImage:ShapeableImageView=itemView.findViewById(R.id.title_image)
val tvHeading: TextView =itemView.findViewById(R.id.tvHeading)
init {
itemView.setOnClickListener{
listener?.onItemClick(adapterPosition)
}
}
}
}
Data :
package com.example.assignment_mad
data class Company(var titleImage:String?=null,var heading:String?=null)
//data class Company(var titleImage:Int,var heading:String)
The xml file ( as you see, actually i need image and text together ) :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="8dp">
<!-- <com.google.android.material.imageview.ShapeableImageView-->
<!-- android:layout_width="80dp"-->
<!-- android:layout_height="80dp"-->
<!-- android:id="#+id/title_image"-->
<!-- android:scaleType="centerCrop"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:shapeAppearanceOverlay="#style/RoundCorner"-->
<!-- android:src="#drawable/company_logo_1"/> -->
<TextView
android:id="#+id/title_image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:text="Self Brief"
android:textSize="16dp"
android:textStyle="bold"
android:layout_marginStart="16dp"
android:layout_marginEnd="32dp"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="#+id/tvHeading"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:text="Candidate Biden Called Saudi Arable a Pareft eaft."
android:textSize="16dp"
android:textStyle="bold"
android:layout_marginStart="16dp"
android:layout_marginEnd="32dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/title_image"
app:layout_constraintTop_toTopOf="parent"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/title_image"
android:background="#color/underline"/>
</androidx.constraintlayout.widget.ConstraintLayout>
These is the problem faced. Or some one else can directly teach me how to set image for realtime database?
My database pic :
Your RecyclerView is showing no item because you are never initializing the adapter variable, which you are setting to your RecyclerView's adapter. Initialize adapter variable inside onViewCreated()
override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) {
super.onViewCreated(itemView, savedInstanceState)
newArrayList= arrayListOf<Company>()
tempArrayList= arrayListOf<Company>()
adapter = NotificationAdapter(newArrayList) //Initialize adapter
getUserdata()
}
Inside onDataChange(), after adding data to newArrayList, notify adapter by calling notifyDataSetChanged() on adapter. It would update the RecyclerView.
private fun getUserdata() {
dbref=FirebaseDatabase.getInstance().getReference("Notification")
dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()){
for (companySnapshot in snapshot.children){
val company=companySnapshot.getValue(Company::class.java)
newArrayList.add(company!!)
}
adapter.notifyDataSetChanged()
}
}
override fun onCancelled(error: DatabaseError) {
Log.w(TAG, "Failed to read value.", error.toException())
}
})
newRecyclerView.layoutManager=LinearLayoutManager(activity)
newRecyclerView.setHasFixedSize(true)
newRecyclerView.adapter = adapter
}
I am trying to get a spinner working with Kotlin, I have spent hours on it but to no avail. Whatever I do, it doesn't respond to items being selected.
Let's start with the code:
This is my xml layout: (only the spinner)
<Spinner
android:id="#+id/unitySelectionSpinner"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="50"
android:gravity="center"
android:textSize="24sp"
/>
My Fragment:
import android.app.Activity
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.navigation.Navigation
import com.epfl.esl.organizer.databinding.FragmentCreateStorageBinding
import com.google.firebase.database.*
import kotlin.collections.ArrayList
class CreateStorageFragment : Fragment(), AdapterView.OnItemSelectedListener {
private lateinit var binding: FragmentCreateStorageBinding
private lateinit var unitID: String
val database: FirebaseDatabase = FirebaseDatabase.getInstance("myDatabase")
val storageRef: DatabaseReference = database.getReference("Units")
var list = ArrayList<String>()
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
Toast.makeText(context, "We got the Key:", Toast.LENGTH_SHORT).show()
var a = 7 / 0
}
override fun onNothingSelected(parent: AdapterView<*>?) {
Toast.makeText(context, "Nothing selected", Toast.LENGTH_SHORT).show()
var b = 7 / 0
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_create_storage, container, false)
// Get the list of names of units from firebase
storageRef.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
// Fill an ArrayList with all the unit names
for(unit in snapshot.children) {
list.add(unit.child("unitName").value.toString())
}
}
override fun onCancelled(error: DatabaseError) {}
})
binding.addObjectButton.setOnClickListener{view: View ->
Navigation.findNavController(view).navigate(R.id.action_createStorageFragment_to_createObjectFragment)
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val spinner: Spinner = binding.unitySelectionSpinner
val spinnerArrayAdapter = ArrayAdapter<String>(activity as Context, android.R.layout.simple_spinner_dropdown_item, list)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = spinnerArrayAdapter
spinner.onItemSelectedListener = this
}
}
I feel that I've tried everything imaginable, including:
-Creating an independent class with the spinner functions (onItemSelected, etc.)
-Put everything in onCreateView, put everything in onViewCreated
-Creating an instance of spinner with AdapterView.OnItemSelectedListener inside onCreateView
Whatever I do the result is always the same: the spinner is populated (all the firebase data is written into it properly) but it doesn't respond when I click on an item in the app. None of the toasts (or the crash that should be caused by the division by zero) are triggered. It simply closes on selection as a normal spinner would do.
I am not sure what I am missing here. Any ideas?
Got the below error when I launched the app in the device... Checked Manifest file, deleted build file and restarted the IDE. Nothing worked out .. Please help!
MainActivity.kt:
package com.bharat.scand_app
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import com.external.scanlibrary.ScanActivity
import com.external.scanlibrary.ScanConstants
import java.io.IOException
class MainActivity : AppCompatActivity() {
private val REQUEST_CODE = 99
lateinit private var scanButton: Button
lateinit private var cameraButton: Button
lateinit private var mediaButton: Button
lateinit private var scannedImageView: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
init()
}
private fun init() {
scanButton = (findViewById<Button>(R.id.scanButton))!!
scanButton.setOnClickListener(ScanButtonClickListener())
cameraButton = (findViewById<Button>(R.id.cameraButton))!!
cameraButton.setOnClickListener(ScanButtonClickListener(ScanConstants.OPEN_CAMERA))
mediaButton = (findViewById<Button>(R.id.galleryButton))!!
mediaButton.setOnClickListener(ScanButtonClickListener(ScanConstants.OPEN_MEDIA))
scannedImageView = (findViewById<ImageView>(R.id.scannedImage))!!
}
fun startScan(preference: Int) {
val intent = Intent(this, ScanActivity::class.java)
intent.putExtra(ScanConstants.OPEN_INTENT_PREFERENCE, preference)
startActivityForResult(intent, REQUEST_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val uri: Uri? = data?.extras!!.getParcelable(ScanConstants.SCANNED_RESULT)
var bitmap: Bitmap? = null
try {
bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
if (uri != null) {
contentResolver.delete(uri, null, null)
}
scannedImageView.setImageBitmap(bitmap)
} catch (e: IOException) {
e.printStackTrace()
}
}
}
private fun convertByteArrayToBitmap(data: ByteArray): Bitmap? {
return BitmapFactory.decodeByteArray(data, 0, data.size)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
val id: Int = item.getItemId()
return if (id == R.id.action_settings) {
true
} else super.onOptionsItemSelected(item)
}
}
private class ScanButtonClickListener : View.OnClickListener {
private var preference = 0
val mActivity : MainActivity
get() {
TODO()
}
constructor(preference: Int) {
this.preference = preference
}
constructor() {}
override fun onClick(v: View?) {
mActivity.startScan(preference)
Log.d("appLog", "Hello World")
}
}
Activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/newLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="#+id/cameraButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="150dp"
android:layout_marginTop="630dp"
android:layout_marginEnd="100dp"
android:layout_marginBottom="50dp"
android:text="Camera"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/galleryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="630dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="50dp"
android:text="Gallery"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/cameraButton"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Error captured in logcat:
--------- beginning of crash
2020-07-09 21:50:00.093 7512-7512/com.myapp.scand_app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.scand_app, PID: 7512
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp.scand_app/com.bharat.scand_app.MainActivity}: kotlin.KotlinNullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3388)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3527)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2123)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7710)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: kotlin.KotlinNullPointerException
at com.bharat.scand_app.MainActivity.init(MainActivity.kt:37)
at com.bharat.scand_app.MainActivity.onCreate(MainActivity.kt:34)
at android.app.Activity.performCreate(Activity.java:7820)
at android.app.Activity.performCreate(Activity.java:7809)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1318)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3363)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3527)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2123)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7710)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
scanButton = (findViewById<Button>(R.id.scanButton))!!
You find scanButton, but there is no button with id of scanButton in activity_main.xml. Your findViewById call return null, and "!!" is the null assertion operator and it is throwing NPE at that line.
Solution : Add another button with id of scanButton in your activity_mail.xml