我有一个包含3个片段的活动,目前我使用的是ViewPager。我想实现MVP并在活动演示者和片段演示者之间进行通信,即:
但我不知道如何以官方方式做到这一点。我可以使用BusEvent,但我认为这不是一个好习惯。
答案 0 :(得分:2)
可以使用
nnn's answer 来完成片段与活动之间的通信,反之亦然,也可以使用ViewModel
和LiveData
来提供更清洁的方式并尊重{{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
活动`
当您使用fragement
或you are bindig it to the lifecycle if the parent
或mViewModel.getToFragmentA().observe()
时,您会将mViewModel.getToFragmentB().observe()
类中的mViewModel.getToAllFragments().observe()
连接到给定的片段或活动,并且将LiveData
方法将在所有观察该方法的类中更新。
答案 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)
要在Fragment
和Activity
之间进行通信(无论是在他们的演示者或他们的班级之间),您需要一个您的活动实现的界面(如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个片段)创建一个演示者是一个坏主意。