Nik*_*zic 11 android android-livedata
我正在使用Android架构组件.我想要的是当用户在Edittext中键入"0"并单击按钮以将Fragment替换为新的,并且如果键入任何其他内容后发布Toast错误消息.在问题是当我从新的Fragment(BlankFragment)返回并再次单击按钮并再次输入"0"并单击时,onchange()被多次调用,因此片段被多次创建
FragmentExample.class:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
manager = getActivity().getSupportFragmentManager();
viewmModel = ViewModelProviders.of(getActivity(), viewModelFactory)
.get(VModel.class);
View v = inflater.inflate(R.layout.fragment_list, container, false);
b = (Button) v.findViewById(R.id.b);
et = (EditText) v.findViewById(R.id.et);
viewmModel.observeData().observe(getActivity(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
if(s.equals("0")) {
BlankFragment fragment = (BlankFragment) manager.findFragmentByTag(DETAIL_FRAG);
if (fragment == null) {
fragment = BlankFragment.newInstance();
}
addFragmentToActivity(manager,
fragment,
R.id.root_activity_detail,
DETAIL_FRAG
);
} else {
Toast.makeText(getContext(), "Wrong text", Toast.LENGTH_SHORT).show();
}
}
});
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewmModel.setData(et.getText().toString());
}
});
return v;
}
private void addFragmentToActivity(FragmentManager fragmentManager, BlankFragment fragment, int root_activity_detail, String detailFrag) {
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(root_activity_detail, fragment, detailFrag).addToBackStack(detailFrag);
transaction.commit();
}
Run Code Online (Sandbox Code Playgroud)
Reopistory类:
public class Repository {
MutableLiveData<String> dataLive = new MutableLiveData<>();
public Repository() {
}
public void setListData(String data) {
dataLive.setValue(data);
}
public MutableLiveData<String> getData() {
return dataLive;
}
}
Run Code Online (Sandbox Code Playgroud)
}
BlankFragment.class:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
listItemViewModel = ViewModelProviders.of(this, viewModelFactory)
.get(VModel.class);
listItemViewModel.setData("");
return inflater.inflate(R.layout.fragment_blank, container, false);
}
Run Code Online (Sandbox Code Playgroud)
Bip*_*Das 15
这是我如何解决这个问题的一个例子。[测试和工作]
viewModel.getLoginResponse().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String response) {
if(getViewLifecycleOwner().getLifecycle().getCurrentState()== Lifecycle.State.RESUMED){
// your code here ...
}
}
});
Run Code Online (Sandbox Code Playgroud)
Jul*_*Neo 10
这里的问题是,当您从活动中删除片段时,片段及其视图模型都不会被销毁.当你回来时,你会livedata在旧的观察者仍然在同一个片段中的时候添加一个新的观察者(如果你添加了观察者onCreateView()).有一篇文章(实际上甚至是一个SO线程)谈论它(使用解决方案).
修复它的简单方法(也在文章中)是在向其添加观察者之前从livingata中删除任何观察者.
更新:在支持lib v28中,一个名为ViewLifeCycleOwner的新LifeCycleOwner应修复此处的更多信息
你不应该创建你的viewmModelinonCreateView而是 in ,onCreate这样你就不会在每次创建视图时向你的数据添加一个监听器。
小智 8
这是你做错了什么......
viewmModel.observeData().observe(getActivity(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
if(s.equals("0")) {
BlankFragment fragment = (BlankFragment) manager.findFragmentByTag(DETAIL_FRAG);
if (fragment == null) {
fragment = BlankFragment.newInstance();
}
addFragmentToActivity(manager,
fragment,
R.id.root_activity_detail,
DETAIL_FRAG
);
} else {
Toast.makeText(getContext(), "Wrong text", Toast.LENGTH_SHORT).show();
}
}
});
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,您可以使用“this”或“viewLifecycleOwner”代替“getActivity()”。
因为当您在observe 方法中传递getActivity() 时,每当您打开您的片段时,您都将观察者的新实例与Activity 而非片段附加在一起。所以即使你杀死了你的片段,观察者也会保持活力。所以当livedata postvalue时,它会向所有的观察者发送数据,因为观察者太多了,那么所有的观察者都会得到通知。因此,您的观察者被调用了太多次。所以你必须像这样观察片段中的实时数据。
viewmModel.observeData().observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
if(s.equals("0")) {
BlankFragment fragment = (BlankFragment) manager.findFragmentByTag(DETAIL_FRAG);
if (fragment == null) {
fragment = BlankFragment.newInstance();
}
addFragmentToActivity(manager,
fragment,
R.id.root_activity_detail,
DETAIL_FRAG
);
} else {
Toast.makeText(getContext(), "Wrong text", Toast.LENGTH_SHORT).show();
}
}
});
Run Code Online (Sandbox Code Playgroud)
但是你的 onchanged 方法仍然会被调用两次。
您可以通过检查 onchanged 方法中的一个条件来停止此操作。
dash_viewModel.getDashLiveData().observe(viewLifecycleOwner, object : Observer<AsyncResponse> {
override fun onChanged(t: AsyncResponse?) {
if(viewLifecycleOwner.lifecycle.currentState==Lifecycle.State.RESUMED){
setData(t)
}
}
})
Run Code Online (Sandbox Code Playgroud)
从我的研究中,我发现,如果使用其相应活动的 ViewModel 进行片段化,那么即使您开始观察实时数据,它也会首先向您发送最近发出的项目。即使你没有从你的片段中调用它。
所以 onChange 方法被调用了两次
当片段处于开始状态时 - 接收最近发出的项目
当片段处于恢复状态时 - 接收片段为 api 发出的调用。
所以改变了我总是像这样在 viewLifecycleOwner 的帮助下检查片段的状态
if(viewLifecycleOwner.lifecycle.currentState==Lifecycle.State.RESUMED){
// if the fragment in resumed state then only start observing data
}
Run Code Online (Sandbox Code Playgroud)
viewlifecycleowner 由 Fragments 和 Activity 提供,因为 Google 直接在支持库 28.0.0 和 androidx 中使用 getViewLifecycleOwner() 方法实现了这个解决方案。viewlifecycleowner 包含有关组件生命周期的信息。
在 Java 中,您可以使用 getViewLifecycleOwner() 而不是 viewlifecycleowner 。
而不是使用getActivityLifecycleOwner,您应该使用片段。
更改
viewmModel.observeData().observe(getActivity(), new Observer<String>() {
Run Code Online (Sandbox Code Playgroud)
至
viewmModel.observeData().removeObservers(this);
viewmModel.observeData().observe(this, new Observer<String>() {
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7627 次 |
| 最近记录: |