Добавить фрагмент из ViewModel в архитектуру 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() и 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 классе


person Ravi    schedule 17.10.2016    source источник


Ответы (2)


Поскольку у вас есть 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.

person yennsarah    schedule 18.10.2016
comment
Плохая практика - сохранять контекст из View в ViewModel. - person kazimad; 22.11.2018
comment
@kazimad вы правы, именно поэтому MVVM был создан в первую очередь, а не для того, чтобы содержать ссылки на материалы, связанные с Android (представлением), в ViewModel. - person Mehdi Kazemi; 09.10.2019
comment
@MeHdi, у меня похожая проблема, что бы ты посоветовал? - person Le Nguyen Duy Anh; 10.02.2020
comment
@LeNguyenDuyAnh Не могли бы вы объяснить подробнее? Вы хотите, чтобы какой-то фрагмент был добавлен в стопку? - person Mehdi Kazemi; 12.02.2020

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

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

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

}

person aschattney    schedule 17.10.2016
comment
да, это доступный способ, но я не уверен, будет ли это хорошей идеей при работе с mvvm. - person Ravi; 17.10.2016
comment
Я хотел бы пойти с идеей EventBus, это лучшее решение, чем первый принятый ответ здесь. - person Jileshl; 14.12.2017
comment
Я хотел бы пойти с идеей EventBus, это лучшее решение, чем первый принятый ответ здесь. - person Jileshl; 14.12.2017