View Model不断创建实时数据实例

时间:2018-12-15 20:44:04

标签: android performance android-layout android-viewmodel

我通过活动的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");
        }
    }

}

5 个答案:

答案 0 :(得分:2)

ThisWorkbook.Path 中定义的执行观察者的数量会不断增加,因为每次单击都将注册新的观察者。您不应该使用ViewModel方法注册观察者。

您应该使用onClick()的{​​{1}}方法或片段的onCreate()方法执行此操作。如果您愿意这样做,则在完成工作时将不需要ActivityonViewCreated机制将为您解决。

但是,如果您真的想回答您的问题,这就是您可以做到的方式

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的目的是公开可观察对象(Livedata)
  • View(Activity / Fragment)的目的是获取这些可观察对象并对其进行观察
  • 只要这些Observables(Livedata)发生更改,该更改就会自动发布到活动的已订阅所有者(活动/片段),因此您不必在onPause / onStop中将其删除,因为这不是强制性的

我可以建议您对代码进行一些更改以解决上述指针的问题

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提供适当的值以通知各个视图的人