我通过活动的onCreate
方法创建了View Model的实例。
ticketViewModel = ViewModelProviders.of(this).get(TicketViewModel.class);
然后我有一个方法AddTicket
,该方法使用viewModel
来启动服务,并根据viewModel
的响应而拒绝加载动画。
public void addTicket(View view){
ticketViewModel.AddTicket(id).observe(this, response ->{
dismissLoadingAnimation();
}
现在,添加票证后,用户可以按下Add Ticket
按钮,然后再次调用addTicket()
方法。
但是这次{2}在ViewModel中定义的observer
被调用两次,导致2次网络调用和2次dismissLoadingAnimation
执行。
如果我继续按下addTicket
按钮,则ViewModel
内部定义的正在执行的观察者的数量会不断增加。
这是我的视图模型代码。
public class TicketViewModel extends AndroidViewModel implements IServiceResponse {
MutableLiveData<String> mObservableResponse = new MutableLiveData<String>();
public MutableLiveData AddTicket(String id){
JsonObject jsonObject= new JsonObject();
jsonObject.addProperty("id", id);
NetworkUtility networkUtility= new NetworkUtility(this, ADD_TICKET);
networkUtility.hitService(URL, jsonObject, RequestMethods.POST);
return mObservableResponse;
}
@Override
public void onServiceResponse(String response, String callType){
if(serviceTag.equalsIgnoreCase(ADD_TICKET)){
mObservableResponse.setValue("success");
}
}
}
答案 0 :(得分:2)
ThisWorkbook.Path
中定义的执行观察者的数量会不断增加,因为每次单击都将注册新的观察者。您不应该使用ViewModel
方法注册观察者。
您应该使用onClick()
的{{1}}方法或片段的onCreate()
方法执行此操作。如果您愿意这样做,则在完成工作时将不需要Activity
。 onViewCreated
机制将为您解决。
但是,如果您真的想回答您的问题,这就是您可以做到的方式
removeObserver
通过Lifecycle
意味着通过您的yourViewModel.yourList.removeObservers(this)
,否则还有另一种方法:
this
答案 1 :(得分:1)
您只需要调用一次observe
,我更喜欢在onResume
中调用,然后在removeObserver
中调用onPause
:
将给定的观察者添加到观察者列表中
您一直在向数据添加侦听器,以便获得多个回调。
修改:
我为Fragment
提取了我现有的代码示例,并重命名了所有内容(我希望如此),这里没有将数据设置为ViewModel
的示例,但在您的情况下应为ticketViewModel.AddTicket(id);
。
public class ListFragment extends Fragment {
private MyViewModel viewModel;
private MyRecyclerViewAdapter recyclerViewAdapter;
private Observer<List<DatabaseObject>> dataObserver;
private RecyclerView recyclerView;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_layout, container, false);
initRecyclerView(rootView, getContext());
initObservers();
return rootView;
}
private void initRecyclerView(View rootView, Context context) {
recyclerViewAdapter = new MyRecyclerViewAdapter(context);
recyclerView = rootView.findViewById(R.id.recycler_view);
recyclerView.setAdapter(recyclerViewAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.addItemDecoration(new DividerNoLastItemDecoration());
}
private void initObservers() {
dataObserver = new Observer<List<DatabaseObject>>() {
@Override
public void onChanged(@Nullable final List<DatabaseObject> data) {
recyclerViewAdapter.setData(data);
}
};
}
@Override
public void onResume() {
super.onResume();
initViewModel();
}
private void initViewModel() {
FragmentActivity activity = getActivity();
if (activity != null) {
viewModel = ViewModelProviders.of(activity).get(MyViewModel.class);
viewModel.getData().observe(activity, dataObserver);
}
}
@Override
public void onPause() {
super.onPause();
if (viewModel != null) {
viewModel.getData().removeObserver(dataObserver);
viewModel = null;
}
}
}
答案 2 :(得分:1)
我有类似的问题。您可以尝试使用SingleLiveEvent
或者,在我更复杂的情况下,我不得不使用自定义观察器。看起来像这样:
public class CustomObserver implements Observer<YourType> {
private MyViewModel mViewModel;
public CustomObserver (){}
public void setViewModel(MyViewModel model) {
mViewModel = model;
}
@Override
public void onChanged(@Nullable YourType object) {
mViewModel.AddTicket(id).removeObserver(this); // removing previous
mmViewModel.refreshTickets(); // refreshing Data/UI
// ... do the job here
// in your case it`s: dismissLoadingAnimation();
}
}
并像这样使用它:
public void addTicket(View view){
ticketViewModel.AddTicket(id).observe(this, myCustomObserver);
}
答案 3 :(得分:1)
我可以建议您对代码进行一些更改以解决上述指针的问题
ViewModel
public class TicketViewModel extends AndroidViewModel implements IServiceResponse {
MutableLiveData<String> mObservableResponse = new MutableLiveData<String>();
public LiveData<String> getResponseLiveData(){
return mObservableResponse;
}
public void AddTicket(String id){
JsonObject jsonObject= new JsonObject();
jsonObject.addProperty("id", id);
NetworkUtility networkUtility= new NetworkUtility(this, ADD_TICKET);
networkUtility.hitService(URL, jsonObject, RequestMethods.POST);
}
@Override
public void onServiceResponse(String response, String callType){
if(serviceTag.equalsIgnoreCase(ADD_TICKET)){
mObservableResponse.setValue("success");
}
}
}
查看
onCreate(){
ticketViewModel = ViewModelProviders.of(this).get(TicketViewModel.class);
observeForResponse();
}
private void observeForResponse(){
ticketViewModel.getResponseLiveData().observe(this, response ->{
//do what has to be updated in UI
}
}
public void addTicket(View view){
ticketViewModel.AddTicket(id);
}
希望这对您有所帮助:)
答案 4 :(得分:0)
如果您愿意进行一些更改,我认为我们可以以更简洁的方式处理它
LiveData用于包含视图的属性值
在ViewModel中
public class TicketViewModel extends AndroidViewModel implements IServiceResponse {
private MutableLiveData<Boolean> showLoadingAnimationLiveData = new MutableLiveData<String>();
public LiveData<Boolean> getShowLoadingAnimationLiveData(){
return showLoadingAnimationLiveData;
}
public void addTicket(String id){
JsonObject jsonObject= new JsonObject();
jsonObject.addProperty("id", id);
NetworkUtility networkUtility= new NetworkUtility(this, ADD_TICKET);
networkUtility.hitService(URL, jsonObject, RequestMethods.POST);
showLoadingAnimationLiveData.setValue(true);
}
@Override
public void onServiceResponse(String response, String callType){
if(serviceTag.equalsIgnoreCase(ADD_TICKET)){
showLoadingAnimationLiveData.setValue(false);
}
}
}
在您的活动/片段的“ onCreate”中
ticketViewModel.getShowLoadingAnimationLiveData().observe(this,showLoadingAnimation->{
if(showLoadingAnimation != null && showLoadingAnimation){
startLoadingAnimation();
}else{
dismissLoadingAnimation();
}
})
主要概念是划分职责, 活动/片段不需要知道正在进行的进程,他们只需要知道子视图的当前属性/状态是什么。
我们需要根据视图在每个更改的属性/状态的ViewModels中维护一个LiveData。 ViewModel需要根据发生的情况处理视图状态。
Activity / Fragment对流程的唯一责任是触发它并忘记它,而ViewModel需要处理所有事情(例如通知存储库进行工作和更改View属性)。
就您而言, “ addTicket”是一个过程,活动/片段不需要知道那里的状态。 关于该过程的活动/片段的唯一责任是触发它。
ViewModel是需要分析进程状态(进行中/成功/失败)并为LiveData提供适当的值以通知各个视图的人