error in fragment when i use FindViewById - android

I'm trying to use fragments to not burden my application with too many activities.
In my mainActivity there is a map, I then created a fragment where there are editText fields, I would like to use these editText to insert numbers to be used as parameters to pass to a function created in another class called navFun.
I tried to write the code but I don't understand why I get these errors when using findViewById:
Unresolved reference: findViewById
this is my fragment code
package uk.co.lorenzopulcinelli.navigationdrawer
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.Button
import android.widget.EditText
import android.widget.Toast
import java.lang.Exception
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [CreatePathFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class CreatePathFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
val mainActivity: MainActivity = MainActivity()
val navFun: NavFun = NavFun(mainActivity.context, mainActivity.mapView)
private lateinit var editTextLatitudineP1: EditText
private lateinit var editTextLongitudineP1: EditText
private lateinit var editTextLatitudineP2: EditText
private lateinit var editTextLongitudineP2: EditText
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? {
// create path between editText points
editTextLatitudineP1 = findViewById<EditText>(R.id.editTextLatitudineP1)
editTextLongitudineP1 = findViewById<EditText>(R.id.editTextLongitudineP1)
editTextLatitudineP2 = findViewById<EditText>(R.id.editTextLatitudineP2)
editTextLongitudineP2 = findViewById<EditText>(R.id.editTextLongitudineP2)
val b = findViewById<Button>(R.id.location)
b.setOnClickListener{
try {
Log.d("Path", "Clicked")
val p1lati: Double = editTextLatitudineP1.text.toString().toDouble()
val p1long: Double = editTextLongitudineP1.text.toString().toDouble()
val p2lati: Double = editTextLatitudineP2.text.toString().toDouble()
val p2long: Double = editTextLongitudineP2.text.toString().toDouble()
println("latitudine: $p2lati, longitudine: $p2long")
navFun.routePath(p1lati, p1long, p2lati, p2long)
mainActivity.mapView.invalidate()
} catch (e: Exception) {
Toast.makeText(context, "Error when entering coordinates", Toast.LENGTH_SHORT).show()
}
}
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_create_path, container, false)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment CreatePathFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
CreatePathFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
and this is my fragment xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
tools:context=".CreatePathFragment"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/crea_percorso"
android:textColor="#color/black"
android:textSize="40sp"
android:textStyle="bold" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/inserisci_le_coordinate_dei_punti_tra_cui_vuoi_creare_un_percorso" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/latitudine_punto_di_partenza" />
<EditText
android:id="#+id/editTextLatitudineP1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/latitudine_p1"
android:inputType="numberSigned|numberDecimal" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/longitudine_punto_di_partenza" />
<EditText
android:id="#+id/editTextLongitudineP1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/longitudine_p1"
android:inputType="numberSigned|numberDecimal" />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/latitudine_punto_di_arrivo" />
<EditText
android:id="#+id/editTextLatitudineP2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/latitudine_p2"
android:inputType="numberSigned|numberDecimal" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/longitudine_punto_di_arrivo" />
<EditText
android:id="#+id/editTextLongitudineP2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/longitudine_p2"
android:inputType="numberSigned|numberDecimal" />
<Button
android:id="#+id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/crea_percorso"
/>
</LinearLayout>

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_create_path, container, false)
// create path between editText points
editTextLatitudineP1 = view.findViewById<EditText>(R.id.editTextLatitudineP1)
editTextLongitudineP1 = view.findViewById<EditText>(R.id.editTextLongitudineP1)
editTextLatitudineP2 = view.findViewById<EditText>(R.id.editTextLatitudineP2)
editTextLongitudineP2 = view.findViewById<EditText>(R.id.editTextLongitudineP2)
val b = findViewById<Button>(R.id.location)
b.setOnClickListener{
try {
Log.d("Path", "Clicked")
val p1lati: Double = editTextLatitudineP1.text.toString().toDouble()
val p1long: Double = editTextLongitudineP1.text.toString().toDouble()
val p2lati: Double = editTextLatitudineP2.text.toString().toDouble()
val p2long: Double = editTextLongitudineP2.text.toString().toDouble()
println("latitudine: $p2lati, longitudine: $p2long")
navFun.routePath(p1lati, p1long, p2lati, p2long)
mainActivity.mapView.invalidate()
} catch (e: Exception) {
Toast.makeText(context, "Error when entering coordinates", Toast.LENGTH_SHORT).show()
}
}
// Inflate the layout for this fragment
return view
}
You must create your view first and than call findViewById on that view.

findViewById will not work inside onCreateView, because at that time the UI is being created, so the views are not initialized yet.
try to link the views inside onViewCreated instead. <-- you can import it using ctrl+O
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
editTextLatitudineP1 = findViewById<EditText>(R.id.editTextLatitudineP1)
//.....the rest of your code
}

Related

Error inflating class fragment Android Studio Kotlin

i want to transfer data from activity to fragment but i get "Error inflating class fragment" I have searched for solution for that problem but still can't.
this is my full code of FirstFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [FirstFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class FirstFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private lateinit var communicator: Communicator
private lateinit var myTextView: TextView
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? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_first, container, false)
myTextView = view.findViewById<View>(R.id.profile_name_text) as TextView
// Gets the data from the passed bundle
val bundle = arguments
val message = bundle!!.getString("mText")
// Sets the derived data (type String) in the TextView
myTextView.text = message
return view
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment FirstFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
FirstFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
my function at Home.kt
fun getData() {
val mFragmentManager = supportFragmentManager
val mFragmentTransaction = mFragmentManager.beginTransaction()
val mFragment = FirstFragment()
val mBundle = Bundle()
val testText = "My Name is Jack"
mBundle.putString("mText",testText)
mFragment.arguments = mBundle
mFragmentTransaction.add(R.id.fragmentContainerView, mFragment).commit()
}
at the fragment_first.xml i want to put the text into the TextView
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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=".Home">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/linear_Layout_home_1"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="30dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:paddingTop="10dp"
android:orientation="horizontal"
android:background="#drawable/rounded_blue_shape"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/profile_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/nama_pengguna"
android:textStyle="bold"
android:textSize="15sp"
android:textColor="#color/cloudy"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
this is code of activity_home.xml
<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=".Home">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/navigation"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<fragment
android:id="#+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/my_nav"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Can anybody help me please?
Base on documentation:
Note: when manually calling setGraph() with arguments, you must not use the app:navGraph attribute when creating the NavHostFragment in XML as that will internally call setGraph() without any arguments, resulting in your graph and start destination being created twice.
docs
You've already defined app: navGraph on your activity(Fragment Container) so you can't call navController. SetGraph from java/kotlin.
Try with remove app:navGraph from Fragment Container
You can pass the data using fragment constructor like this:
fun getData() {
val mFragmentManager = supportFragmentManager
val mFragmentTransaction = mFragmentManager.beginTransaction()
val testText = "My Name is Jack"
val mFragment = FirstFragment(testText)
mFragmentTransaction.add(R.id.fragmentContainerView, mFragment).commit()
}
And fetch it in the fragment like this:
class FirstFragment(private val someText: String): Fragment() {
private lateinit var myTextView: TextView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_first, container, false)
myTextView = view.findViewById<View>(R.id.profile_name_text) as TextView
// Sets the derived data (type String) in the TextView
myTextView.text = someText
return view
}
}
Also seeing your fragment_first.xml layout, you might wanna put it like this:
<RelativeLayout
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">
<TextView
android:id="#+id/profile_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/nama_pengguna"
android:textStyle="bold"
android:textSize="15sp"
android:textColor="#color/cloudy"/>
</RelativeLayout>
Not sure what caused your issue. But noticed you are using Jetpack navigation.
And you're trying to pass data to the start destination of the graph.
Here is an official doc for dealing with your case:
Pass data to the start destination.
And below are some of the code I tried myself, just for your reference:
I think in your MainActivity.kt, you would have something like this:
val navController = findNavController(R.id.fragmentContainerView)
navController.setGraph(R.navigation.my_nav, Bundle().apply {
putString("name", "My name is xx")
})
And in the first fragment, retrieve the parameter:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val name = arguments?.get("name")
Log.w("xx", "$name")
Edit: I updated the findNavController(R.id.fragmentContainerView) and navController.setGraph(R.navigation.my_nav according to the ids in your code.

Null object reference for ArrayAdapter

I am attempting to adapt an ArrayList to an AutoCompleteTextView in a Fragment. I have had this working on another program, where I am applying the adapter in the MainActivity.
The error I am getting is:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.AutoCompleteTextView.setAdapter(android.widget.ListAdapter)' on a null object reference
My Fragment code - newFlightFrament.kt:
package com.android.joncb.flightlogbook
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.widget.ArrayAdapter
import com.android.joncb.flightlogbook.ExtFunctions.CreateList
import com.android.joncb.flightlogbook.dto.AirlineDTO
import com.google.gson.GsonBuilder
import kotlinx.android.synthetic.main.fragment_new_flight.*
private const val ARG_PARAM1 = "airlines"
class newFlightFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var airlineNameOnly = ArrayList<String>()
private var airlineFSCodeOnly = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
// Log.e("args", param1)
println(param1)
val gson = GsonBuilder().create()
val tempList :List<AirlineDTO> = gson.fromJson(param1,Array<AirlineDTO>::class.java).toList()
val airlines :ArrayList<AirlineDTO> = arrayListOf(AirlineDTO())
airlines.addAll(tempList)
airlineNameOnly = CreateList(airlines, "airlineName")!!
airlineFSCodeOnly = CreateList(airlines, "FS")!!
}
// val adapter = context?.let {
// ArrayAdapter<String>(
// it,
// android.R.layout.simple_list_item_1,
// airlineNameOnly
// )
// }
val adapter = ArrayAdapter<String>(requireActivity().baseContext,android.R.layout.simple_list_item_1,airlineNameOnly)
actxtAirlineName.setAdapter(adapter)
}
}
My Fragment XML - fragment_new_flight.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="#color/colorPrimary"
tools:context=".newFlightFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/lblNewFlightInstruction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="#dimen/abPadding"
android:text="#string/lblNewFltInstr"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/abPadding"
android:paddingVertical="8dp"
android:text="#string/airline_name"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/lblNewFlightInstruction" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/abPadding"
android:paddingVertical="8dp"
android:text="#string/fsCode"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/actxtAirlineName" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/abPadding"
android:paddingVertical="8dp"
android:text="#string/fltNumber"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/etxtFSCode" />
<AutoCompleteTextView
android:id="#+id/actxtAirlineName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="#string/airline_name"
android:paddingStart="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/textView3"
app:layout_constraintTop_toTopOf="#+id/textView" />
.
.
.
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
I am getting the error when I setAdapter:
actxtAirlineName.setAdapter(adapter)
Note in my commented out section above this call I have tried another approach, which results in the same error.
I can confirm that the ArrayList airlineNameOnly is populated correctly.
Any ideas are good ideas.
Thanks.
You forget override onCreateView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_new_flight, container, false)
}
Change onCreate to onViewCreated, when onCreate call view doesn't inflate
I cannot see where you inflated your fragment's view. Perhaps there's the issue?
Change your code according to mine
First include this
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout. fragment_new_flight, container, false)
}
arguments?.let {
param1 = it.getString(ARG_PARAM1)
// Log.e("args", param1)
println(param1)
val gson = GsonBuilder().create()
val tempList :List<AirlineDTO> = gson.fromJson(param1,Array<AirlineDTO>::class.java).toList()
val airlines :ArrayList<AirlineDTO> = arrayListOf(AirlineDTO())
airlines.addAll(tempList)
airlineNameOnly = CreateList(airlines, "airlineName")!!
airlineFSCodeOnly = CreateList(airlines, "FS")!!
// val adapter = context?.let {
// ArrayAdapter<String>(
// it,
// android.R.layout.simple_list_item_1,
// airlineNameOnly
// )
// }
val adapter = ArrayAdapter<String>(requireActivity().baseContext,android.R.layout.simple_list_item_1,airlineNameOnly)
actxtAirlineName.setAdapter(adapter)
}
}
Hope it will work Thankew! Happy coding!

Recyclerview Item onclick overlays the next fragment instead of replacing it

I have these activity, fragments, its viewmodels, and their adapter. I can already call the next fragment on click of a recyclerview item, but the new fragment overlays on the first fragment.
Refer to screenshot below:
Next screenshot is the old fragment view:
As for the mainactivity:
class MainActivity : AppCompatActivity(), RecyclerViewClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home,
R.id.navigation_messages,
R.id.navigation_notifications,
R.id.navigation_account
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_home, HomeFragment.newInstance(), "dormList")
.commit()
}
}
override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
val detailsFragment = dormDetailsFragment.newInstance(dorms)
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_home, detailsFragment, "Dorm Details")
.addToBackStack(null)
.commit()
}
}
HomeFragment:
class HomeFragment : Fragment(), RecyclerViewClickListener {
private lateinit var factory: HomeViewModelFactory
private lateinit var viewModel: HomeViewModel
private var callback : RecyclerViewClickListener? = null
companion object {
fun newInstance(): HomeFragment {
return HomeFragment()
}
}
override fun onAttach(context: Context) {
super.onAttach(context)
if(context is RecyclerViewClickListener) callback = context
else throw ClassCastException("$context must implement Callback")
}
override fun onDetach() {
super.onDetach()
callback = null
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val api = DormsAPI()
val repository = DormRepository(api)
factory = HomeViewModelFactory(repository)
viewModel = ViewModelProviders.of(this, factory).get(HomeViewModel::class.java)
viewModel.getDorms()
viewModel.dorms.observe(viewLifecycleOwner, Observer { dorms ->
recyclerViewDorms.also{
it.layoutManager = LinearLayoutManager(requireContext())
it.setHasFixedSize(true)
it.adapter = dormAdapter(dorms, this)
}
})
}
override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
when(view.id){
R.id.button_reserve -> {
// TODO: Go to new account if not signed up, etc...
Toast.makeText(requireContext(), "Reserve button clicked", Toast.LENGTH_LONG).show()
}
R.id.layoutBox -> {
// TODO: Go to Dorm Details
callback?.onRecyclerViewItemClick(view, dorms)
}
}
}
}
Home View Model
class HomeViewModel(private val repository: DormRepository) : ViewModel() {
private lateinit var job: Job
private val _dorms = MutableLiveData<List<Dorms>>()
val dorms: LiveData<List<Dorms>>
get() = _dorms
fun getDorms() {
job = Coroutines.ioThenMain(
{ repository.getDorms() },
{ _dorms.value = it }
)
}
override fun onCleared() {
super.onCleared()
if(::job.isInitialized) job.cancel()
}
}
Interface:
interface RecyclerViewClickListener {
fun onRecyclerViewItemClick(view: View, dorms: Dorms)
}
Details Fragment:
class dormDetailsFragment : Fragment() {
companion object {
private const val DORMS = "model"
fun newInstance(dorms: Dorms): dormDetailsFragment{
val args = Bundle()
args.putSerializable(DORMS, dorms)
val fragment = dormDetailsFragment()
fragment.arguments = args
return fragment
}
}
private lateinit var viewModel: DormDetailsViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val fragmentDormDetailsBinding =
FragmentDormDetailsBinding.inflate(inflater,container,false)
val model = arguments!!.getSerializable(DORMS) as Dorms
fragmentDormDetailsBinding.dormDetails = model
return fragmentDormDetailsBinding.root
}
}
Home Fragment Layout
<?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:id="#+id/fragment_home">
<TextView
android:id="#+id/text_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/refreshLayout">
<androidx.recyclerview.widget.RecyclerView
tools:listitem="#layout/layout_home"
android:id="#+id/recyclerViewDorms"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Details Layout
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<import type="android.view.View" />
<variable
name="dormDetails"
type="com.pptt.roomy.data.models.Dorms" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.pptt.roomy.ui.home.dormDetails.DormDetailsFragment"
android:id="#+id/DormDetailsFrag">
<ImageView
app:image="#{dormDetails.image}"
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:background="#drawable/propertysample"
/>
<TextView
android:text="#{String.valueOf(dormDetails.dormPrice)}"
tools:text="Php 2500"
android:id="#+id/textViewPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="6dp"
android:layout_marginStart="10dp"
android:textSize="20sp"
android:textStyle="normal"
android:textColor="#000000"
app:layout_constraintTop_toBottomOf="#id/image"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:text="#{dormDetails.dormName}"
tools:text="Dorm ni Jupa"
android:id="#+id/textViewPropertyName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="1dp"
android:layout_marginStart="10dp"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#000000"
app:layout_constraintTop_toBottomOf="#id/textViewPrice"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:text="#{dormDetails.dormType}"
tools:text="1 BR with Dining and Kitchen"
android:id="#+id/textViewRoomType"
android:layout_below="#id/textViewPropertyName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:layout_marginLeft="40dp"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="#+id/textViewPropertyName"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:text="#{dormDetails.dormAddress}"
android:id="#+id/textViewAddress"
android:layout_marginBottom="5dp"
tools:text="455 San Jose II St., Brgy. 425, Sampaloc, Manila"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Small"
android:padding="5dp"
android:layout_marginLeft="40dp"
android:layout_width="wrap_content"
android:textAlignment="center"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#+id/textViewRoomType"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:text="#{dormDetails.dormDetails}"
android:id="#+id/textViewDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="A very long textarea to contain dorm description. Should be multiline"
android:padding="5dp"
android:layout_marginLeft="20dp"
app:layout_constraintTop_toBottomOf="#id/textViewAddress"
app:layout_constraintLeft_toLeftOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Anything else that's needed will be edited for later.
Remove these lines:
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_home, HomeFragment.newInstance(), "dormList")
.commit()
}
You're adding one HomeFragment via the NavHostFragment and another manually. You don't need to manually add Fragment when using Navigation.
You should also be updating your onRecyclerViewItemClick to use navigate() as per the Navigate to a destination documentation:
override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
val navController = findNavController(R.id.nav_host_fragment)
// If you're using Safe Args, use the ID generated from
// the navigation graph and make sure you have
// an argument of the correct type
navController.navigate(
HomeFragmentDirections.actionHomeToDetails(dorms))
}
You might find it helpful to look at the Pass data between destinations documentation to see how to create an <argument> in your graph for your Dorms object and how to set up Safe Args to generate the Directions class for you.

Trying to display an entire collection from my Firestore database using RecyclerView and Fragments - Kotlin

I have tried many different tutorials and haven't been able to relate any to my application. My application in a gist displays a user's medication that they are taking. Here is my data class...
import java.util.HashMap
class LocalMedication {
var m_medicationName: String? = null
var m_medicationQty: String? = null
var m_medicationType: String? = null
var m_medicationExpDate: String? = null
var m_medicationStatus: Boolean = false
constructor() {}
constructor(medicationName: String, medicationQty: String, medicationType: String, medicationExpDat : String, medicationStatus : Boolean) {
this.m_medicationName = medicationName
this.m_medicationType = medicationType
this.m_medicationQty = medicationQty
this.m_medicationExpDate = medicationExpDat
this.m_medicationStatus = medicationStatus
}
fun toMap(): Map<String, Any> {
val result = HashMap<String, Any>()
result.put("medicationName", m_medicationName!!)
result.put("medicationType", m_medicationType!!)
result.put("medicationQty", m_medicationQty!!)
result.put("medicationExpDate", m_medicationExpDate!!)
result.put("medicationStatus", m_medicationStatus!!)
return result
}
}
Here is my view holder class
package com.example.home_med.viewHolder
import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.home_med.R
class medicationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var medicationName: TextView
var medicationType: TextView
var medicationQty: TextView
init {
medicationName = view.findViewById(R.id.rv_medicationName)
medicationType = view.findViewById(R.id.rv_medicationType)
medicationQty = view.findViewById(R.id.rv_medicationQty)
}
}
Here is my fragment
class LocalMedication : Fragment() {
private var adapter: FirestoreRecyclerAdapter<LocalMedication, medicationViewHolder>? = null
private var firestoreDB: FirebaseFirestore? = null
private var firestoreListener: ListenerRegistration? = null
private var medList = mutableListOf<LocalMedication>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_main)
firestoreDB = FirebaseFirestore.getInstance()
val recyclerView = recyclerview as? RecyclerView
val mLayoutManager = LinearLayoutManager(context)
recyclerView?.layoutManager = mLayoutManager
recyclerView?.itemAnimator = DefaultItemAnimator()
loadMedication()
firestoreListener = firestoreDB!!.collection("notes")
.addSnapshotListener(EventListener { documentSnapshots, e ->
if (e != null) {
Log.e(TAG, "Listen failed!", e)
return#EventListener
}
medList = mutableListOf()
if (documentSnapshots != null) {
for (doc in documentSnapshots) {
val note = doc.toObject(LocalMedication::class.java)
note.m_medicationName = doc.id
medList.add(note)
}
}
adapter!!.notifyDataSetChanged()
recyclerView?.adapter = adapter
})
}
override fun onDestroy() {
super.onDestroy()
firestoreListener!!.remove()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding: FragmentLocalMedicationBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_local_medication, container, false)
binding.viewMedicationButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToViewMedication())
}
binding.addMedicationButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToAddMedication())
}
binding.homeButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToHome2())
}
setHasOptionsMenu(true)
return binding.root
}
private fun loadMedication() {
val query = firestoreDB!!.collection("notes")
val response = FirestoreRecyclerOptions.Builder<LocalMedication>()
.setQuery(query, LocalMedication::class.java)
.build()
adapter = object : FirestoreRecyclerAdapter<LocalMedication, medicationViewHolder>(response) {
override fun onBindViewHolder(holder: medicationViewHolder, position: Int, model: LocalMedication) {
val note = medList[position]
holder.medicationName.text = note.m_medicationName
holder.medicationType.text = note.m_medicationType
holder.medicationQty.text = note.m_medicationQty
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): medicationViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recyclerview_item, parent, false)
return medicationViewHolder(view)
}
override fun onError(e: FirebaseFirestoreException) {
Log.e("error", e!!.message)
}
}
adapter!!.notifyDataSetChanged()
recyclerview?.adapter = adapter
}
public override fun onStart() {
super.onStart()
adapter!!.startListening()
}
public override fun onStop() {
super.onStop()
adapter!!.stopListening()
}
}
Here is my recyclerViewItem XML file
<LinearLayout 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:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/rv_medicationName"
style="#style/word_title"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="#android:color/holo_orange_light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/rv_medicationQty"
style="#style/word_title"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="#android:color/holo_orange_light"
app:layout_constraintStart_toEndOf="#+id/rv_medicationName"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/rv_medicationType"
style="#style/word_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:background="#android:color/holo_orange_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/rv_medicationQty"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
Here is my localMedications XML file
<layout 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"
tools:context=".LocalMedication">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
android:text="LOCAL MEDICATION"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.478"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="543dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="#android:color/darker_gray"
app:layout_constraintBottom_toTopOf="#+id/homeButton"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView"
tools:listitem="#layout/recyclerview_item" />
<Button
android:id="#+id/viewMedicationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="100dp"
android:layout_marginBottom="100dp"
android:text="View Med"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="#+id/addMedicationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginBottom="100dp"
android:text="Add Medication"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/homeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="59dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="103dp"
android:text="Home"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/viewMedicationButton"
app:layout_constraintStart_toEndOf="#+id/addMedicationButton"
app:layout_constraintTop_toBottomOf="#+id/addMedicationButton"
app:layout_constraintVertical_bias="0.972" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Here is what my database looks like...
Datatbase
Any help or guidance would be great. It runs the application, but in the Logs, it says "RecyclerView: No adapter attached; skipping layout"
The problem in your code lies in the fact that the names of the fields in your LocalMedication class are different than the name of the properties in your database. You have in your LocalMedication class a field named m_medicationName while in your database I see it as medicationName and this is not correct. The names must match. Behind the scene, Kotlin is creating a Java class with a getter named getM_medicationName() so Firebase is looking in the database for a field named m_medicationName and not medicationName.
There are two ways in which you can solve this problem. The first one would be to remove the data in your database and add it again using field names (m_medicationName, m_medicationQty etc) that exist in your LocalMedication class.
If you are not allowed to use the first solution, then the second approach will be to use annotations in front of your public fields. So you should use the PropertyName annotation in front of every field. So in your LocalMedication class, a field should look like this:
#get:PropertyName("medicationName")
#set:PropertyName("medicationName")
public var m_medicationName: String? = null
As explained in my answer from the following post:
I am trying to get the correct reference to my Firebase Database child and set the values in my RecyclerView but I am having some issues
It's for Firebase realtime database but the same rules apply to Cloud Firestore.

Binding variable is null.. How to let the observer in UI wait till the queried Livedata is excuted from database?

I am trying to get data from database and then bind it in fragment to the XML.
So I have repository getting the data from the DB to the ViewModel and the UI fragment is observing the results and then binding the data to the XML.
But the problem is that the app is crushing saying that data is null Even though I am voiding the null data in the observer.
I've tried the to execute the query on the background thread it seems to be working properly the returning the data (Photo).
I think the problem is that the query is taking time and the Observer in the fragment is not waiting till the query is done.
So the query is okay and I am following exactly Google samples but could not figure out the problem.
Thanks in advance.
_PhotoRepository
class PhotoRepository #Inject constructor(
private val photoDao: PhotoDoa
) {
fun loadPhotoById(photoId: Int): LiveData<Photo> {
// var photo: Photo? = null
// this is working and i am getting the photo object
// appExecutors.diskIO().execute {
photo = photoDao.getObjectPhotoById(photoId)
}
return photoDao.getPhotoById(photoId)
}
}
_PhotoViewModel
class PhotoViewModel #Inject constructor(private val photoRepository:
PhotoRepository) :
ViewModel() {
private var _photoId = MutableLiveData<Int>()
val photoId: LiveData<Int>
get() = _photoId
val photo: LiveData<Photo> = Transformations
.switchMap(_photoId) { id ->
photoRepository.loadPhotoById(id)
}
fun setId(photoId: Int) {
// if (_photoId.value == photoId){
// return
// }
_photoId.value = photoId
}
}
_PhotoFragment
class PhotoFragment : Fragment(), Injectable {
#Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
var binding by autoCleared<FragmentPhotoBinding>()
lateinit var photoViewModel: PhotoViewModel
var photo = Photo()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate<FragmentPhotoBinding>(
inflater,
R.layout.fragment_photo,
container,
false
)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val params = PhotoFragmentArgs.fromBundle(arguments!!)
photoViewModel = ViewModelProviders.of(
this,
viewModelFactory).get(PhotoViewModel::class.java)
photoViewModel.setId(params.photoId)
// photoViewModel.photo.removeObservers(viewLifecycleOwner)
photoViewModel.photo.observe(viewLifecycleOwner, Observer {
if (it != null) {
binding.photo = it
}
})
}
}
_ The Query in the Doa class
#Query(" SELECT * FROM Photo WHERE id = :id")
abstract fun getPhotoById ( id: Int): LiveData<Photo>
_ fragment_photo.xml
<layout
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">
<data>
<import type="com.mustafa.pixabayapp.models.Photo"/>
<variable
name="photo"
type="Photo"/>
<import type="com.mustafa.pixabayapp.utils.StringUtils" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/photo_fragment_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:imageUrl="#{photo.webFormatURL}"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#color/colorTransparentDark"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="#+id/photo_fragment_tags"
style="#style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{StringUtils.getTags(photo.tags)}"
tools:text="TEST - TEST - TEST"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/photo_fragment_user_name"
style="#style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="#{StringUtils.byUser(photo.userName)}"
tools:text="By: Mustafa"/>
<TextView
android:id="#+id/photo_fragment_comments"
style="#style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="4dp"
android:drawableStart="#drawable/ic_comment"
android:text="#{StringUtils.getCommentsAsString(photo.commentsCount)}"
tools:text="2222"/>
<TextView
android:id="#+id/photo_fragment_favorites"
style="#style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_toStartOf="#id/photo_fragment_comments"
android:drawableStart="#drawable/ic_favorite"
android:text="#{StringUtils.getFavoritesAsString(photo.favoritesCount)}"
tools:text="2222"/>
<TextView
android:id="#+id/photo_fragment_likes"
style="#style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_toStartOf="#id/photo_fragment_favorites"
android:drawableStart="#drawable/ic_like"
android:text="#{StringUtils.getLikesAsString(photo.likesCount)}"
tools:text="2222"/>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
</layout>
_The Error message:
java.lang.IllegalArgumentException:
Parameter specified as non-null is null:
method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter
userName at com.mustafa.pixabayapp.utils.StringUtils.byUser(Unknown
Source:2)at com.mustafa.pixabayapp.databinding.FragmentPhotoBindingImpl.
executeBindings(FragmentPhotoBindingImpl.java:138)
Yes, your assumption with "it takes time" is correct. The layout wants to draw something as soon its bind and at this time photo is not loaded yet.
You could handle the null value in StringUtils.byUser() or adding a null check in the layout like here: Data binding: set property if it isn't null

Categories

Resources