1

I have framelayout in activity and two fragments that I need to attach to the activity depending on the user's choise. When I attach one fragment and change orientation, my fragment gest destrotroyed with activity. How to keep the state of fragment inside activity?

This is my menuActivity which has framelayout.

class MenuActivity : AppCompatActivity(), OptionsFragment.PassFragment {

    private val TAG = "Menu"
    private lateinit var binding: ActivityMenuBinding
    private lateinit var informationViewModel: InformationViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMenuBinding.inflate(layoutInflater)
        setContentView(binding.root)
        informationViewModel = ViewModelProvider(this).get(InformationViewModel::class.java)
        Log.i(TAG, "onCreate: code: ${informationViewModel.hashCode()}")
        if (informationViewModel.fragment != null) {
            showFragment(informationViewModel.fragment!!)
        } else {
            showFragment(OptionsFragment())
        }

    }

    private fun showFragment(fragment: Fragment) {
        supportFragmentManager.beginTransaction().replace(R.id.container, fragment)
            .commit()
    }

    override fun onPassFragment(fragment: Fragment) {
        informationViewModel.fragment = fragment
    }

}

This is my first fragment which should appear first in activity and it has two textviews for two fragments.

class OptionsFragment : Fragment(R.layout.options_fragment) {

    private lateinit var txtPersonal: TextView
    private lateinit var txtSecond: TextView
    private lateinit var informationViewModel: InformationViewModel
    private lateinit var passFragment: PassFragment

    private val TAG = "OptionsFragment"


    interface PassFragment {
        fun onPassFragment(fragment: Fragment)
    }


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        txtPersonal = view.findViewById(R.id.person_det)
        txtSecond = view.findViewById(R.id.trading_currency)
        informationViewModel = ViewModelProvider(this).get(InformationViewModel::class.java)
        Log.i(TAG, "onViewCreated:  code:  ${informationViewModel.hashCode()} ")

        txtPersonal.setOnClickListener {
            passFragment(PersonalInfFragment())
            requireActivity().supportFragmentManager.beginTransaction()
                .replace(R.id.container, PersonalInfFragment()).commit()
        }


        txtSecond.setOnClickListener {
            passFragment(TradingFragment())
            requireActivity().supportFragmentManager.beginTransaction()
                .replace(R.id.container, TradingFragment()).commit()
        }
    }


    private fun passFragment(fragment: Fragment) {
        try {
            passFragment = activity as PassFragment
            passFragment.onPassFragment(fragment)
        } catch (ex: ClassCastException) {

        }
    }

}

Let's say from above options fragment, I opened my second TradingFragment and showed some information from retrofit using the same viewmodel.


class TradingFragment : Fragment(R.layout.currency_trading) {

    private val TAG = "TradingFragment"

    private lateinit var informationViewModel: InformationViewModel

    private lateinit var rec_view: RecyclerView
    private lateinit var btnSearch: Button
    private lateinit var adapter: TradingAdapter
    private lateinit var rangeSeek: RangeSlider
    private lateinit var txtStartDate: TextView
    private lateinit var txtFinishData: TextView
    private lateinit var spinner: Spinner
    private var from = 0
    private var to = 0

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        btnSearch = view.findViewById(R.id.btnSearch)
        rec_view = view.findViewById(R.id.rec_view)
        rangeSeek = view.findViewById(R.id.rangeSlider)
        txtStartDate = view.findViewById(R.id.txtFrom)
        txtFinishData = view.findViewById(R.id.txtTo)
        spinner = view.findViewById(R.id.spinner)
        informationViewModel = ViewModelProvider(this).get(InformationViewModel::class.java)

        val cur_time = "${System.currentTimeMillis()}".substring(0, 10)
        rangeSeek.valueTo = Integer.valueOf(cur_time) * 1.0f

        initRecyclerView()

        rangeSeek.addOnSliderTouchListener(object : RangeSlider.OnSliderTouchListener {

            override fun onStartTrackingTouch(slider: RangeSlider) {

            }

            override fun onStopTrackingTouch(slider: RangeSlider) {
                changeDateValueForText(slider.values.get(0).toInt(), slider.values.get(1).toInt())
            }

        })

        btnSearch.setOnClickListener {
            startSearchingCurrencyTrading()
        }

    }

    private fun startSearchingCurrencyTrading() {
        val pair = spinner.selectedItem.toString()
        informationViewModel.startRequestingCurrency(pair, from, to)
    }

    private fun changeDateValueForText(start: Int, finish: Int) {
        from = start
        to = finish
        val startDate = Date(start * 1000L)
        val finishDate = Date(finish * 1000L)
        val df = SimpleDateFormat("dd:MM:yyyy")
        txtStartDate.text = df.format(startDate)
        txtFinishData.text = df.format(finishDate)
    }

    private fun initRecyclerView() {
        adapter = TradingAdapter()
        rec_view.adapter = adapter
        rec_view.layoutManager = LinearLayoutManager(requireActivity())
        informationViewModel.returnCurrentTrading().observe(this) {
            if (it != null) {
                adapter.updateTradingItems(it)
            } else {
                adapter.updateTradingItems(listOf())
            }
        }


    }

}

This is my current solution it worked, but I lost my previous query result to retrofit that was being showed on the tradingfragment before orientation change.

Stefano Sansone
  • 2,377
  • 7
  • 20
  • 39
Bekzhan
  • 485
  • 5
  • 11

1 Answers1

1

Rotation of the screen is defined a configuration change and If you want to preserve the state of your UI I suggest you to implent a ViewModel as described here

However, you have several options to preserve the state of the UI, the choose depends on your needs, all possible scenarios are well explained in the official documentation.

enter image description here

Stefano Sansone
  • 2,377
  • 7
  • 20
  • 39