Are passing data between a service to a fragment using a MutableLiveData. Accordenly to a Log.d statement the data is recived. But when i try to use TextView to display the data i get null. It think a delay makes it null. Is there a way to delay or update the textview so i can display the data?
DashbordFragment.kt
class DashbordFragment : Fragment() {
private var locationList = mutableListOf<LatLng>()
var liveLatLng = MutableLiveData<LatLng>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
sendActionCommandToService(Constants.ACTION_SERVICE_START)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
observerTrackerService()
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_dashbord, container, false)
}
lateinit var binding : FragmentDashbordBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentDashbordBinding.bind(view)
binding.btGotostation.setOnClickListener {
startActivity(Intent(requireContext(),StationsActivity::class.java))
}
binding.btGotostatistics.setOnClickListener {
findNavController().navigate(DashbordFragmentDirections.actionDashbordFragmentToStatisticsFragment())
}
binding.btGotolinediagram.setOnClickListener {
findNavController().navigate(DashbordFragmentDirections.actionDashbordFragmentToLineDiagramFragment())
}
binding.btMap.setOnClickListener {
findNavController().navigate(DashbordFragmentDirections.actionDashbordFragmentToMapsFragment())
}
binding.latlon.text = liveLatLng.value.toString()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.dashboard_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return super.onOptionsItemSelected(item)
}
private fun observerTrackerService(){
TrackerService.locationList.observe(viewLifecycleOwner) {
if (it != null) {
locationList = it
Log.d("LocationList",locationList.toString())
}
}
TrackerService.liveLatLng.observe(viewLifecycleOwner){
Log.d("LiveLatLng", it.toString())
}
Log.d("LocationList", "Tester")
}
private fun sendActionCommandToService(action: String){
Intent(
requireContext(),
TrackerService::class.java
).apply {
this.action = action
requireContext().startService(this)
}
}
fragment_dashbord.xml
<FrameLayout 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"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|center"
android:text="@string/dashboard"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/go_to_station"
android:layout_marginStart="24dp"
android:layout_marginTop="54dp"
android:id="@ id/bt_gotostation"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/GoogleMap"
android:layout_marginStart="24dp"
android:layout_marginTop="140dp"
android:id="@ id/btMap"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/statistics_desc"
android:layout_marginTop="240dp"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/development_bar_chart"
android:layout_marginStart="24dp"
android:layout_marginTop="290dp"
android:id="@ id/bt_gotostatistics"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/development_line_diagram"
android:layout_marginStart="24dp"
android:layout_marginTop="360dp"
android:id="@ id/bt_gotolinediagram"/>
<TextView
android:id="@ id/latlon"
android:layout_width="100dp"
android:layout_height="100dp"
android:text="@string/statistics_desc"
android:layout_marginTop="500dp"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
</FrameLayout>
CodePudding user response:
You are setting this in onViewCreated
which is called earlier than you received the data.
Instead you can set an observer as follows in onViewCreated
example :
liveLatLng.observe(this , Observer {
it?.let{
binding.latlon.text = it.toString()
}
})
and set the value as follows
TrackerService.liveLatLng.observe(viewLifecycleOwner){
liveLatLng.value = it // hoping this is of type LatLng
}
Note: Consider this according to android dev docs
Make sure to store LiveData objects that update the UI in ViewModel objects, as opposed to an activity or fragment, for the following reasons: To avoid bloated activities and fragments. Now these UI controllers are responsible for displaying data but not holding data state. To decouple LiveData instances from specific activity or fragment instances and allow LiveData objects to survive configuration changes.
from developer docs
CodePudding user response:
This binding.latlon.text = liveLatLng.value.toString()
has nothing in common with livedata. When used correctly, your code should look like this binding.latlon = liveLatLng
and no need for delay, LiveData
will do it for you. To reach this all you need is to check LiveData, DataBinding and BindingAdapter.
Small hint for required binding variable
<import type="com.google.type.LatLng" />
<variable
name="latlon"
type="androidx.lifecycle.MutableLiveData<LatLng>" />