Адаптер не поддерживается во фрагменте после поворота экрана - PullRequest
0 голосов
/ 03 мая 2020

Я создаю приложение Simple Form entry Android, используя компоненты дизайна материалов. В основном работает с нижней навигацией и текстовыми полями. Проблема, с которой я сталкиваюсь, заключается в установке адаптера в раскрывающемся списке textfield . Когда приложение открывается, я получаю надлежащую функциональность, но после поворота адаптер кажется забытым, и единственная опция в выпадающем меню - это текущая выбранная опция перед вращением. Функция setupViews() в CalculatorFragment вызывается, но по какой-то причине адаптер настроен неправильно. Представление extIntFront не доступно нигде в коде, кроме функции setupViews(), которая вызывается в функции onCreateView CalculatorFragment.

MainActivity.kt

class MainActivity : AppCompatActivity() {

private val binding: ActivityMainBinding by lazy {
    ActivityMainBinding.inflate(layoutInflater)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val view = binding.root
    setContentView(view)
    setupViews()
}

private fun setupViews() = binding.apply {

    val navController = findNavController(R.id.nav_host_fragment)

    navView.setupWithNavController(findNavController(R.id.nav_host_fragment))
    navView.setOnNavigationItemSelectedListener { item ->
        when (item.itemId) {
            R.id.navigation_item_calculator -> {
                if (navController.currentDestination?.id == R.id.navigation_fragment_builder) {
                    navController.navigate(BuilderFragmentDirections.actionBuilderToCalculator())
                }
            }
            R.id.navigation_item_builder -> {
                if (navController.currentDestination?.id == R.id.navigation_fragment_calculator) {
                    navController.navigate(CalculatorFragmentDirections.actionCalculatorToBuilder())
                }
            }
        }
        true
    }
}
}

CalculatorFragment.kt (макет, как определено в R.id.navigation_fragment_calculator)

class CalculatorFragment : BaseFragment() {        
    private val viewModel by viewModels<CalculatorViewModel>()

    private val binding: FragmentCalculatorBinding by lazy {
        FragmentCalculatorBinding.inflate(layoutInflater)
    }

    override fun onCreateView (
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        observeEvents()
        setupViews()
        return binding.root
    }

    private fun observeEvents() {
        viewModel.observeActions {
            handleActions(it)
        }

        viewModel.observeState {
            handleState(it)
        }
    }

    ...

    private fun setupViews() = binding.apply {
        ...
        val items = listOf(getString(R.string.external), getString(R.string.internal))
        val adapter = ArrayAdapter(requireContext(), R.layout.list_item, items)
        extIntFront.setAdapter(adapter)
        extIntFront.setText(getString(R.string.external),false)
        ...
    }
}

Базовый фрагмент.kt

abstract class BaseFragment : Fragment() {

protected val compositeDisposable = CompositeDisposable()

protected inline fun <reified A : Any, reified S : Any> RxViewModel<A, S>.observeActions(
    crossinline actionListener: (A) -> Unit = {}
) {
    actionsObservable.subscribeBy(onNext = {
        actionListener(it)
    }, onError = {
        Timber.e("Unable to listen for actions: $it")
    }).addTo(compositeDisposable)
}

protected inline fun <reified A : Any, reified S : Any> RxViewModel<A, S>.observeState(
    crossinline stateListener: (S) -> Unit = {}
) {
    stateLiveData.observe(this@BaseFragment, Observer {
        stateListener(it)
    })
}

override fun onDestroy() {
    super.onDestroy()
    compositeDisposable.clear()
}
}

RxViewModel.kt

abstract class RxViewModel<A, S> : ViewModel() {

    private val _actions = RxEventSender<A>()
    val actionsObservable = _actions.observable

    protected fun action(action: A) = _actions.send(action)

    private val _state = MutableLiveData<S>()
    val stateLiveData = _state as LiveData<S>
    protected var state: S?
        get() = _state.value
        set(value) = _state.postValue(value)
}

1 Ответ

0 голосов
/ 04 мая 2020

Я нашел решение, которое работает и заключается в добавлении адаптера к View в onViewStateRestored(savedInstanceState: Bundle?). Это потому, что я считаю, что viewModel восстанавливает состояние View, и onViewStateRestored вызывается после того, как viewModel восстанавливает состояние View. Другие функции с именем onCreate onCreateView onActivityCreated вызываются до того, как viewModel восстановит View и удалит адаптер. Я до сих пор не уверен, почему viewModel стирает адаптер. Мой код теперь выглядит следующим образом.

override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
        val items = listOf(getString(R.string.external), getString(R.string.internal))
        val adapter = ArrayAdapter(requireContext(), R.layout.list_item, items)
        binding.extIntFront.setAdapter(adapter)
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...