Как обмениваться данными между активностью и фрагментом через класс ViewModel в Android?

Мне было интересно, можно ли передать данные String, объявленные в классе Activity, и передать данные String в класс ViewModel, а затем передать данные в класс Fragment.

Класс ViewModel

class TimeTableViewModel extends ViewModel {

private MutableLiveData<String> start_time_str = new MutableLiveData<>();

void send_StartTime(String start_Time){
    start_time_str.setValue(start_Time);
}

LiveData<String> get_StartTime(){
    return start_time_str;
}}

В классе ViewModel у меня есть MutableLiveData<String> start_time_str, и он был инициализирован как new MutableLiveData<>();

Я хотел бы использовать функцию void send_StartTime(String start_Time) в классе Activity, чтобы установить значение аргумента String start_Time и вызвать start_time_str в классе Fragment.

Класс активности

@Override
public boolean onOptionsItemSelected(MenuItem item){
    switch (item.getItemId()){
        case android.R.id.home:
            finish();
            break;
        case R.id.add_schedule_save:
            String start_time_str = startTime.getText().toString();
            Intent intent_restart0 = new Intent(TimeTable_Add_New_Schedule.this, MainActivity.class);
            startActivity(intent_restart0);
            TimeTableViewModel timeTableViewModel = new TimeTableViewModel();
            timeTableViewModel.send_StartTime(start_time_str);
            Toast.makeText(this,""+start_time_str,Toast.LENGTH_LONG).show();
            break;
    }
    return super.onOptionsItemSelected(item);
}

Класс фрагмента

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    TimeTableViewModel timeTableViewModel = new TimeTableViewModel();
    timeTableViewModel.get_StartTime().observe(getViewLifecycleOwner(), new Observer<String>() {
        @Override
        public void onChanged(String s) {
            mon_textView_11.setText(s);
        }
    });
}

В классе Fragment я вызываю функцию get_StartTime(), чтобы получить start_time_str и установить значение String для моего TextView. Я думаю, что start_time_str был успешно установлен функцией timeTableViewModel.send_StartTime(start_time_str); в классе активности, потому что Toast.maketext работает как шарм. Однако TextView ничего не отображается. Я проверил, что цвет текста не белый, поэтому при правильном вызове строкового значения оно должно появиться на экране. Если у вас есть какие-либо предложения, я хотел бы услышать ваш совет. Большое тебе спасибо.

введите описание изображения здесь


person Community    schedule 27.03.2020    source источник


Ответы (3)


Это действительно зависит от того, как вы создаете свой ViewModel экземпляр. Теперь вы создаете ViewModel с помощью его конструктора, но это неправильный способ. Вам следует использовать ViewModelProvider или методы расширения, созданные командой Google.

Если вы выберете ViewModelProvider, сделайте это так:

TimeTableViewModel viewModel = new ViewModelProvider(this).get(TimeTableViewModel.class);

Важно передать правильный контекст of вызову метода. Если вы находитесь во фрагменте и будете просто использовать getContext() вместо getActivity(), вы не получите тот же экземпляр, который был создан в Activity. Вы создадите новый экземпляр ViewModel, который будет ограничен только внутри жизненного цикла фрагмента. Поэтому важно использовать контекст активности обеих частей, чтобы получить один и тот же экземпляр.

Часть деятельности:

TimeTableViewModel viewModel = new ViewModelProvider(this).get(TimeTableViewModel.class);

Часть фрагмента:

TimeTableViewModel viewModel = new ViewModelProvider(getActivity()).get(TimeTableViewModel.class);

Важно, чтобы ваш фрагмент находился внутри того же действия, которое использует этот ViewModel.

Но ребята из Google упростили нам задачу с помощью некоторых методов расширения. Но насколько мне известно, они работают только в классах Kotlin. Итак, если у вас есть код Kotlin, вы можете объявить свой ViewModel просто так:

private val quizViewModel: TimeTableViewModel by activityViewModels()

Для фрагмента с областью видимости ViewModel вам нужно написать что-то вроде этого:

private val quizViewModel: TimeTableViewModel by viewModels()

Но вам нужно добавить зависимость Kotlin ktx в ваш build.gradle файл проекта. Например так:

implementation 'androidx.fragment:fragment-ktx:1.1.0'
person BVantur    schedule 27.03.2020
comment
Я ценю твой ответ. Я не мог поделиться данными с помощью класса ViewModel, потому что фрагмент не находится внутри моего класса активности, поэтому я создал новый фрагмент, а затем заменил его на класс активности. И работает отлично. Большое тебе спасибо. - person ; 27.03.2020
comment
Если вы используете компонент "Навигация", вы также можете ограничить свои модели просмотра с помощью графа навигации следующим образом: val myViewModel: TimeTableViewModel by navGraphViewModels(R.id.navigation_graph). Рад, что смог помочь. :) - person BVantur; 27.03.2020
comment
в чем польза от этого? - person pentexnyx; 09.08.2020
comment
Какую часть вы имеете в виду? ViewModels с областью навигации? - person BVantur; 10.08.2020
comment
В соответствии с последними указаниями команды Android мы обычно используем Single Activity в сочетании с компонентом навигации для создания наших приложений. Если это так, то мы фактически создаем синглтон, который живет во всем приложении, если мы используем Activity ViewModel. Чтобы избежать этого, мы могли бы разбить наше приложение на разные элементы навигации и правильно определить область действия наших логических компонентов в зависимости от варианта использования навигации. Например, нам не нужен OnboardingManager на главном экране вошедшего в систему пользователя. - person BVantur; 12.08.2020
comment
Я это уже знаю. Мой вопрос: есть ли разница между val myViewModel: TimeTableViewModel от navGraphViewModels (R.id.navigation_graph) и myViewModel = ViewModelProvider.AndroidViewModelFactory (Application ()). Create (MyViewModel :: class.java) - person pentexnyx; 13.08.2020

Не используйте new, поскольку он создает новый ViewModel для фрагмента, создайте его следующим образом:

val viewModel = ViewModelProviders.of(this).get(MyFavouritesViewModel.class);

Это вернет тот же экземпляр, что и действие, используемое во фрагменте.

person Rajendra Dabhi    schedule 27.03.2020

Если вы используете архитектуру Android и хотите поделиться activityViewModel в своем fragments.

Чтобы получить viewModels в fragment, используйте приведенный ниже код:

private val fragmentViewModel: Fragment1ViewModel by viewModels()
private val activityViewModel: MainActivityViewModel by activityViewModels()

и в MainActivity используйте код ниже:

private val activityViewModel: MainActivityViewModel by viewModels()
person mhKarami    schedule 18.12.2020