Добавить фрагмент из ViewModel в архитектуру MVVM

#android #android-fragments #mvvm #android-databinding #android-mvvm

#Android #android-фрагменты #mvvm #android-привязка данных #android-mvvm

Вопрос:

Я использую DataBinding и следую архитектуре MVVM, теперь я застрял на том, как добавить новый фрагмент, ViewModel поскольку нам нужно определенное событие щелчка ViewModel . Вот мой MainViewModel класс

 public class MainViewModel {
    private Context context;

    public MainViewModel (Context context) {
        this.context = context;
    }
    public void onClick(View v) {

    }
}
 

вот мой xml, в котором я определил событие щелчка

 <layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="viewmodel"
            type="com.example.MainViewModel" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
         <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{viewmodel::onClick}"
            android:text="click me"/>
    </RelativeLayout>
</layout>
 

теперь, как я могу получить supportFragmentManager или childFragmentManager из моего класса ViewModel? Я пытался использовать activity.getSupportFragmentManager() and activity.getChildFragmentManager() , но у него нет такого метода.

Я знаю, что мы можем добавить фрагмент со следующим кодом

 getActivity().getSupportFragmentManager().beginTransaction()
            .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out, android.R.anim.fade_in, android.R.anim.fade_out).
            add(R.id.container, fragment, "").addToBackStack("main").commit();
 

но как это сделать в ViewModel классе

Ответ №1:

Поскольку у вас есть свой Context доступный, у вас есть две возможности:

 public class MainViewModel {
    private Context context;

    public MainViewModel (Context context) {
        this.context = context;
    }

    public void onClick(View v) {
        //use context:
        ((AppCompatActivity) context).getSupportFragmentManager();

        //OR use the views context:
        if(v.getContext() instanceof AppCompatActivity) {
            ((AppCompatActivity) v.getContext()).getSupportFragmentManager();
        }            
    }    
}
 

Может быть полезно проверить, является ли контекст экземпляром вашей активности (например MainActivity ) или AppCompatActivity , или, если это null так, перед вызовом любого метода.

Комментарии:

1. Плохой практикой является сохранение контекста из представления в ViewModel

2. @kazimad вы правы, именно поэтому MVVM был создан в первую очередь, а не для хранения ссылок на материалы, связанные с Android (view), в ViewModel.

3. @MeHdi у меня похожая проблема, что бы вы тогда предложили?

4. @LeNguyenDuyAnh Не могли бы вы объяснить подробнее? Вы хотите, чтобы какой-то фрагмент был добавлен в backstack?

Ответ №2:

Я не знаю, возможно ли это, но вот что я предлагаю:

Определите интерфейс и позвольте действию или фрагменту реализовать этот интерфейс

 public interface FragmentProvider {
    void showFragment(...);
}
 

Передайте экземпляр FragmentProvider в вашу ViewModel

 public class MainViewModel {
    private Context context;
    private FragmentProvider provider;

    public MainViewModel (FragmentProvider provider) {
        this.provider = provider;
   }

   public void onClick(View v) {
        // delegate the action
        provider.showFragment(...);
   }
 

}

Комментарии:

1. да, это доступный способ, но я не уверен, будет ли это хорошей идеей или нет при работе с mvvm.

2. Я хотел бы согласиться с идеей EventBus, что это лучшее решение, чем первый принятый ответ здесь.

3.Я хотел бы согласиться с идеей EventBus, что это лучшее решение, чем первый принятый ответ здесь.