Android MVP - 如何在活动演示者和片段演示者之间进行通信

问题描述 投票:24回答:6

我有一个包含3个片段的活动,目前我使用的是ViewPager。我想实现MVP并在活动演示者和片段演示者之间进行通信,即:

  • 将数据从活动演示者传递到片段演示者
  • 从片段演示者向活动演示者发送事件
  • ...

但我不知道如何以官方方式做到这一点。我可以使用BusEvent,但我认为这不是一个好习惯。

android mvp
6个回答
2
投票

片段和活动之间的通信或反之亦然可以通过使用 nnn's answer 来完成,或者你可以使用ViewModelLiveData女巫提供一种更清洁的方式并尊重fragmentsactivities的生命周期,这可以避免编写几行代码以防止aa不可见的fragment从背景上接收数据。

首先,你扩展ViewModel类,初始化Livedata和一些辅助方法。

public class MyViewModel extends ViewModel {
private MutableLiveData<String> toFragmentA, toFragmentB;
private MutableLiveData<List<String>>  toAllFragments;

public MyViewModel() {
    toFragmentA = new MutableLiveData<>();
    toFragmentB = new MutableLiveData<>();
    toAllFragments = new MutableLiveData<>();
}

public void changeFragmentAData(String value){
    toFragmentA.postValue(value);
}
public void changeFragmentBData(String value){
    toFragmentB.postValue(value);
}
public void changeFragmentAllData(List<String> value){
    toAllFragments.postValue(value);
}

public LiveData<String> getToFragmentA() {
    return toFragmentA;
}

public LiveData<List<String>> getToAllFragments() {
    return toAllFragments;
}

public LiveData<String> getToFragmentB() {
    return toFragmentB;
}

}

然后你在你的活动上初始化ViewModel

public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private TabLayout tabLayout;
MyViewModel mViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mViewModel = ViewModelProviders.of(this)
            .get(MyViewModel.class);

    viewPager.setAdapter(new Adapter(getSupportFragmentManager()));


}

}

读取片段中的数据:

 @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

    mViewModel.getToAllFragments().observe(this, new Observer<List<String>>() {
        @Override
        public void onChanged(List<String> s) {
            myList.addAll(s);
            //do something like update a RecyclerView
        }
    });

    mViewModel.getToFragmentA().observe(this, new Observer<String>() {


        @Override
        public void onChanged(String s) {
            mytext = s;
            //do something like update a TextView
        }
    });
}

要更改任何实时数据的值,您可以使用任何片段或活动中的方法之一:

changeFragmentAData();
changeFragmentBData();
changeFragmentAllData();

幕后发生了什么:

当你使用mViewModel = ViewModelProviders.of(this).get(MyViewModel.class)时,你正在创建一个ViewModel的n实例并将其绑定到片段的给定活动的生命周期,因此视图模型仅在activityfragement停止时才会被破坏。如果你使用mViewModel = ViewModelProviders.of(getActivity())。get(MyViewModel.class)you are bindig it to the lifecycle if the parentactivity`

当你使用mViewModel.getToFragmentA().observe()mViewModel.getToFragmentB().observe()mViewModel.getToAllFragments().observe()你将LiveData类中的MyViewModel连接到给定的片段或活动时,onChange()方法的值会在观察该方法的所有类中更新。

我建议个人见证有关LivedataViewModel的一些研究,你可以在youtubethis link


0
投票

根据我的理解,对于你的UseCase,假设ActivityA有一个viewPager有3个片段(FragmentA,FragmentB,FragmentC)。

ActivityA有ActivityPresenterA

FragmentA有FragmentPresenterA

根据MVP,FragmentPresenterA应仅负责FragmentA的所有逻辑和业务流,并且只应与FragmentA通信。因此,FragmentPresenterA无法直接与ActivityPresenterA通信。

对于从Fragment到Activity的通信,不应该介绍演示者,这应该像我们在非MVP架构中进行通信一样,即在界面的帮助下进行。

同样适用于活动到片段通信。

对于Activity和Fragment之间的通信,请阅读here


0
投票

您可以为该案例使用一个演示者。

使用Activity Presenter获取片段所需的所有数据。然后创建一个接口类并将其实现到您的片段。

例如:

为PageAFragment创建一个公共接口(此接口将从活动到片段的数据桥接)。并使用您的界面方法处理演示者要查看的结果。

这是我为接收的数据创建的接口类的示例。对于参数,你可以选择你想要的东西,这取决于你的需要,但对我来说,我选择模型。

public interface CallbackReceivedData {
    void onDataReceived(YourModel model);
}

在MainActivity类中,检查附加到您的活动中的片段的实例。在提交片段后放置检查实例。

public class MainActivity extends AppCompatActivity{

  private CallbackReceivedData callbackReceivedData;

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      //after commit the fragment
    if (fragment instanceof PageAFragment){
            callbackReceivedData = (CallbackReceivedData)fragment;
    }

  }
  //this is the example method of MainActivity Presenter, 
  //Imagine it, as your view method.
  public void receivedDataFromPresenter(YourModel model){
      callbackReceivedData.onDataReceived(model);
  }

}

我假设receivedDataFromPresenter是我们视图的接收方法,并将数据提供给演示者。

现在我们将数据从演示者传递给callbackReceivedData

在PageAFragment中实现CallbackReceivedData并覆盖onDataReceived方法。现在,您可以将活动中的数据传递给片段。

public class PageAFragment extends Fragment implements CallbackReceivedData{

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public void onDataReceived(YourModel model) {

    }
}

注意:替代方法,您可以使用Bundle并使用setArguments传递数据。

如果您想将片段中的事件发送到活动,您可以遵循此想法。

创建一个Interface类并将其实现到MainActivity并覆盖从接口到活动的方法,对于我的情况,我这样做。

这是我的CallbackSendData类。

public interface CallbackSendData {
    void sendDataEvent(String event);
}

为您的MainActivity实现CallbackSendData接口并覆盖sendDataEvent方法。

public class MainActivity extends AppCompatActivity implements CallbackSendData{

  private CallbackReceivedData callbackReceivedData;

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

     //after commit the fragment
     if (fragment instanceof PageAFragment){
         callbackReceivedData = (CallbackReceivedData)fragment;
     }

  }

  //this is the example method of MainActivity Presenter, 
  //Imagine it, as your view method.
  public void receivedDataFromPresenter(YourModel model){
      callbackReceivedData.onDataReceived(model);
  }    


  @Override
  public void sendDataEvent(String event){
     //You can now send the data to your presenter here.
  }



}

对于你的PageAFragment,你需要使用attach方法来构建你的界面。一旦片段与其活动相关联,就调用attach方法。如果您想了解片段的生命周期,请单击此链接:https://developer.android.com/reference/android/app/Fragment.html

public class PageAFragment extends Fragment implements CallbackReceivedData{

    private CallbackSendData callbackSendData;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }

    @Override
    public void onDataReceived(YourModel model) {
        //Received the data from Activity to Fragment here.
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 
    container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.PagerAFragment, container, 
    false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle 
    savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Button Eventbutton;

        Eventbutton = view.findViewById(R.id.event_button);
        Eventbutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                callbackSendData.sendDataEvent("send Data sample");
            }
        });
    }

   @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try{
            callbackSendData = (CallbackSendData) context;
        }catch (ClassCastException e){
            e.printStackTrace();
        }
    }

}

现在,您可以使用CallbackSendData将活动数据发送到片段。

注意:如果您对项目使用依赖注入,则更容易,您可以使用Dagger2库。

祝好运。


0
投票

要在FragmentActivity之间进行通信(无论是在他们的演示者还是他们的类之间),您需要一个您的活动实现的界面(如ShoppingInteractor)。

这样你就可以在片段中调用((ShoppingInteractor)getActivity()).doSomething()。如果您希望活动的演示者处理任务,则需要在活动内部的doSomething中调用演示者。

您可以使用另一个接口对片段执行相同操作,并在活动内部调用片段的交互器。

您甚至可以在这些界面中使用Presenter getPresenter()来访问实际的演示者。 (((ShoppingInteractor)getActivity()).getPresenter().sendData(data))。片段也一样。


0
投票

如果你想使用MVP,第一步是为每个View创建一个演示者,我的意思是,如果你有3个片段,那么将有3个演示者。我认为为4个视图(活动和3个片段)创建一个演示者是个坏主意。


0
投票

动态数据:

以下是使用rxjava2,dagger2和moxy的示例。

附加条件:

  • 演示者不依赖于视图的生命周期
  • 一位主持人 - 一个观点。这些视图不会相互分享演示者,一个视图只有一个演示者。

该解决方案类似于EventBus,但使用具有有限生命周期的Subject。它位于活动开始时创建的组件中,并在退出时被销毁。活动和片段都具有对它的隐式访问权限,它们可以更改值并以自己的方式响应它。

示例项目:https://github.com/Anrimian/ViewPagerMvpExample

静态数据:

只需在片段中使用参数就可以了。

© www.soinside.com 2019 - 2024. All rights reserved.