Home > OS >  Can i monitor a variable changed in another class in kotlin?
Can i monitor a variable changed in another class in kotlin?

Time:01-03

Im in a fragment1 and i want go to fragment2 if an event occurred in a class called from the fragment1. I have tried a callback of fuction: function in Class call a function in fragment1 to go in fragment but i collect this error:

Process: com.example.ilmiogioco, PID: 7992java.lang.IllegalStateException: Method addObserver must be called on the main thread
at androidx.lifecycle.LifecycleRegistry.enforceMainThreadIfNeeded(LifecycleRegistry.java:317)
at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:172)
at androidx.savedstate.SavedStateRegistryController.performRestore(SavedStateRegistryController.java:61)
at androidx.navigation.NavBackStackEntry.<init>(NavBackStackEntry.java:88)
at androidx.navigation.NavBackStackEntry.<init>(NavBackStackEntry.java:73)
at androidx.navigation.NavController.navigate(NavController.java:1138)
at androidx.navigation.NavController.navigate(NavController.java:944)
at androidx.navigation.NavController.navigate(NavController.java:877)
at androidx.navigation.NavController.navigate(NavController.java:863)
at androidx.navigation.NavController.navigate(NavController.java:851)
at com.example.ilmiogioco.FullscreenFragmentSolo.follow(FullscreenFragmentSolo.kt:77)
at com.example.ilmiogioco.Solo.SpaceView.update(SpaceView.kt:276)
at com.example.ilmiogioco.Solo.SpaceView.run(SpaceView.kt:120)
at java.lang.Thread.run(Thread.java:919)

EDIT: I have fullscreenfragmentsolo (fragment1) that want in gameoverfragment (fragment2) if the class spaceview called in fullscreenfragmentsolo collect a lost game. The function follow() is called by spaceview for return in fullscreenfragmentsolo (maybe this is the thread error).

 class FullscreenFragmentSolo : Fragment() {

private var spaceView: SpaceView? = null
private lateinit var backgroundMusic: MediaPlayer
private lateinit var window: Window
private var binding: FragmentFullscreenSoloBinding? = null
object size{
    var x = 0
    var y = 0
}


override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    (activity as AppCompatActivity?)!!.supportActionBar!!.hide()
    getActivity()?.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    val soundEffects = SoundEffects(requireContext())

    soundEffects.playSound(SoundEffects.backgroundMusic)

    val outMetrics = DisplayMetrics()

    getActivity()?.getWindow()?.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
    window = activity?.getWindow()!!
    window.attributes.width
    window.attributes.height

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
        val display = activity?.display
        display?.getRealMetrics(outMetrics)
    } else {
        @Suppress("DEPRECATION")
        val display = activity?.windowManager?.defaultDisplay
        @Suppress("DEPRECATION")
        display?.getMetrics(outMetrics)
    }

    size.y = outMetrics.heightPixels
    size.x = outMetrics.widthPixels

    backgroundMusic = MediaPlayer.create(requireContext(), R.raw.background_music)
    backgroundMusic.isLooping = true
    backgroundMusic.start()
    val fragmentBinding = FragmentFullscreenSoloBinding.inflate(inflater, container, false)
    binding = fragmentBinding
    fragmentBinding.root
    spaceView = SpaceView(requireContext(), size, this)

    return spaceView
}
fun follow(){

    findNavController().navigate(R.id.action_fullscreenFragmentSolo_to_gameoverFragment)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    binding?.soloFragment = this
}

override fun onResume() {
    super.onResume()

    spaceView?.resume()
}
fun stopFunction() {
    spaceView?.stop()
}

override fun onPause() {
    super.onPause()

    backgroundMusic.release()
    spaceView?.pause()

}
override fun onDestroyView() {
    super.onDestroyView()
    binding = null
}

GameoverFragment:

open class GameoverFragment : Fragment() {
private var binding: GameoverFragmentBinding? = null


override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    // Inflate the layout for this fragment
    val fragmentBinding = GameoverFragmentBinding.inflate(inflater, container, false)
    binding = fragmentBinding
    return fragmentBinding.root
    return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    binding?.gameoverFragment = this
}
fun Menu(){
    findNavController().navigate(R.id.action_gameoverFragment_to_startFragment)
}

> override fun onDestroyView() {
>     super.onDestroyView()
>     binding = null }

Can you help me?

CodePudding user response:

This exception is due to your code calling (through navigation) the LifecycleRegistry.addObserver from a thread other than the Main thread. You have to ensure that you call the navigation from the main thread.

Change to this in the follow() function

import android.os.Handler
import android.os.Looper

// ...

fun follow() {
    Handler(Looper.getMainLooper()).post {
        findNavController().navigate(R.id.action_fullscreenFragmentSolo_to_gameoverFragment)
    }
}
  • Related