【问题标题】:How to keep fragment in activity during orientation change?如何在方向改变期间保持片段处于活动状态?
【发布时间】:2021-08-05 14:49:50
【问题描述】:

我在活动中有框架布局和两个片段,我需要根据用户的选择附加到活动中。当我附加一个片段并改变方向时,我的片段被活动破坏了。如何在activity中保持fragment的状态?

这是我的 menuActivity,它有框架布局。

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
    }

}

这是我的第一个片段,应该首先出现在活动中,它有两个片段的两个文本视图。

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) {

        }
    }

}

假设从上面的选项片段中,我打开了我的第二个 TradingFragment 并使用相同的视图模型显示了一些来自改造的信息。


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())
            }
        }


    }

}

这是我当前有效的解决方案,但是我丢失了之前的查询结果以进行改造,该结果在方向改变之前显示在交易片段上。

【问题讨论】:

    标签: android kotlin android-activity screen-orientation fragment-lifecycle


    【解决方案1】:

    屏幕旋转定义为配置更改,如果您想保留 UI 的状态,我建议您按照 here 的描述实现 ViewModel

    但是,您有几个选项来保留 UI 的状态,选择取决于您的需要,所有可能的场景在 official documentation 中都有很好的解释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 2022-06-28
      • 2018-08-03
      相关资源
      最近更新 更多