Android MVP - 如何在活动演示者和片段演示者

时间:2016-04-19 03:00:33

标签: android mvp

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

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

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

6 个答案:

答案 0 :(得分:2)

可以使用 nnn's answer 来完成片段与活动之间的通信,反之亦然,也可以使用ViewModelLiveData来提供更清洁的方式并尊重{{1 }}和fragments可以省去编写几行代码的尝试,以防止不可见的activities在后​​台接收数据。

首先,您扩展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或{ {1}}已停止。如果您使用mViewModel = ViewModelProviders.of(getActivity())。get(MyViewModel.class)activity活动`

当您使用fragementyou are bindig it to the lifecycle if the parentmViewModel.getToFragmentA().observe()时,您会将mViewModel.getToFragmentB().observe()类中的mViewModel.getToAllFragments().observe()连接到给定的片段或活动,并且将LiveData方法将在所有观察该方法的类中更新。

我建议您对MyViewModel结尾onChange()做一些个人研究,您可以在youtubethis link

答案 1 :(得分:0)

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

ActivityA有ActivityPresenterA

FragmentA有FragmentPresenterA

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

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

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

对于活动和片段之间的通信,请阅读here

答案 2 :(得分:0)

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

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

例如:

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

这是我为接收数据创建的接口类的示例。对于参数,您可以根据需要选择您想要的,但对我来说,我选择型号。

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

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

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库。

<强>古德勒克。

答案 3 :(得分:0)

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

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

您可以使用其他界面对片段执行相同操作,并在活动中调用片段的交互器。

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

答案 4 :(得分:0)

动态数据:

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

附加条件:

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

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

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

这只是一个例子,绝不会以这种方式改变主题。

静态数据:

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

答案 5 :(得分:0)

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