如何在片段中使用 ViewModel?

huangapple go评论87阅读模式
英文:

How to use ViewModel in a fragment?

问题

我正在使用MVVM架构。我有一个活动和几个片段,我想在活动中对API进行请求,然后使用ViewModel根据获取的数据在片段中显示它们。我应该如何做?我当前的解决方案不起作用:

活动:

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.init();

片段:

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.getRoutes().observe(getActivity(), new Observer<List<RoutesResponse>>() {
    @Override
    public void onChanged(List<RoutesResponse> routes) {

                //显示数据
    }
});

仓库:

public class RemoteRepository {

private ApiRequest apiRequest;
private MutableLiveData<List<RoutesResponse>> routes = new MutableLiveData<>();

public RemoteRepository() {
    apiRequest = RetrofitRequest.getInstance().create(ApiRequest.class);
}

public MutableLiveData<List<RoutesResponse>> getRoutes() {

    apiRequest.getRoutes()
            .enqueue(new Callback<List<RoutesResponse>>() {
                @Override
                public void onResponse(Call<List<RoutesResponse>> call, Response<List<RoutesResponse>> response) {

                    if (response.isSuccessful())
                        routes.setValue(response.body());
                }

                @Override
                public void onFailure(Call<List<RoutesResponse>> call, Throwable t) {
                    Log.i("Failure", "Fail!");
                }
            });

        return routes;
    }
}

ViewModel:

public class ViewModelRoutesFragment extends AndroidViewModel {

private RemoteRepository remoteRepository;
private LiveData<List<RoutesResponse>> routes;

public ViewModelRoutesFragment(@NonNull Application application) {
    super(application);
}

public void init() {
    remoteRepository = new RemoteRepository();
    routes = remoteRepository.getRoutes();
}

public LiveData<List<RoutesResponse>> getRoutes() {
        return routes;
    }
}

目前出现空指针错误。如何正确避免这个错误?

java.lang.NullPointerException: 尝试在空对象引用上调用虚拟方法 'void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)' 
英文:

I'm using the MVVM architecture. I have an activity and a few fragments, I would like to make a request in the API in the activity, and then using ViewModel, thanks to the obtained data, to display them in the fragment. How should I do this? My current solution that doesn't work:

Activity:

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.init();

Fragment:

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.getRoutes().observe(getActivity(), new Observer&lt;List&lt;RoutesResponse&gt;&gt;() {
    @Override
    public void onChanged(List&lt;RoutesResponse&gt; routes) {

                //Show data
    }
});

Repository:

public class RemoteRepository {

private ApiRequest apiRequest;
private MutableLiveData&lt;List&lt;RoutesResponse&gt;&gt; routes = new MutableLiveData&lt;&gt;();

public RemoteRepository() {
    apiRequest = RetrofitRequest.getInstance().create(ApiRequest.class);
}

public MutableLiveData&lt;List&lt;RoutesResponse&gt;&gt; getRoutes() {

    apiRequest.getRoutes()
            .enqueue(new Callback&lt;List&lt;RoutesResponse&gt;&gt;() {
                @Override
                public void onResponse(Call&lt;List&lt;RoutesResponse&gt;&gt; call, Response&lt;List&lt;RoutesResponse&gt;&gt; response) {

                    if (response.isSuccessful())
                        routes.setValue(response.body());
                }

                @Override
                public void onFailure(Call&lt;List&lt;RoutesResponse&gt;&gt; call, Throwable t) {
                    Log.i(&quot;Failure&quot;, &quot;Fail!&quot;);
                }
            });

        return routes;
    }
}

ViewModel:

public class ViewModelRoutesFragment extends AndroidViewModel {

private RemoteRepository remoteRepository;
private LiveData&lt;List&lt;RoutesResponse&gt;&gt; routes;

public ViewModelRoutesFragment(@NonNull Application application) {
    super(application);
}

public void init() {
    remoteRepository = new RemoteRepository();
    routes = remoteRepository.getRoutes();
}

public LiveData&lt;List&lt;RoutesResponse&gt;&gt; getRoutes() {
        return routes;
    }
}

Currently getting a null error. How can I avoid it properly?

java.lang.NullPointerException: Attempt to invoke virtual method &#39;void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)&#39; on a null object reference

答案1

得分: 10

在Fragment中
使用

viewModelRoutesFragment = new ViewModelProvider(requireActivity()).get(ViewModelRoutesFragment.class);

而不是

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
英文:

in Fragment
Use

viewModelRoutesFragment = new ViewModelProvider(requireActivity()).get(ViewModelRoutesFragment.class);

instead of

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);

答案2

得分: 6

基本上,我们正在尝试在活动(activity)和片段(fragment)之间共享 ViewModel。因此,在活动创建期间,我们必须创建 ViewModel 的实例:

viewModelRoutesFragment = new ViewModelProvider(requireActivity()).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.init();

在片段中,我们还需要重用 ViewModelRoutesFragment,在 onViewCreated() 方法中获取 ViewModel 实例并观察 LiveData:

viewModelRoutesFragment = new ViewModelProvider(requireActivity()).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.getRoutes().observe(getActivity(), new Observer<List<RoutesResponse>>() {
    @Override
    public void onChanged(List<RoutesResponse> routes) {
       // 更新 UI
    }
});
英文:

Basically, we are trying to share the viewmodel across the activity and fragment.
so while during the activity creation we have to create the instance of viewmodel

viewModelRoutesFragment = new ViewModelProvider(requireActivity()).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.init();

In fragment also we need to reuse the ViewModelRoutesFragment so in onViewCreated()
get the instance of the ViewModel and observe the live data

viewModelRoutesFragment = new ViewModelProvider(requireActivity()).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.getRoutes().observe(getActivity(), new Observer&lt;List&lt;RoutesResponse&gt;&gt;() {
    @Override
    public void onChanged(List&lt;RoutesResponse&gt; routes) {
       // updation of UI
    }
});

答案3

得分: 1

你不需要在活动中使用视图模型引用。您应该在活动内部拥有片段的实例。您的片段已经持有对ViewModel的引用。从活动中删除这些行 -> :

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.init();

确保在活动中初始化您的片段。您的活动只是一个容器块,实际上会使用片段管理器替换片段。如果您正在与片段一起使用,它不需要任何ViewModel。

此外,在以下行的下方,在片段内调用此方法 viewModelRoutesFragment.init();

 viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
英文:

You don't need your view model reference in the activity. You should have an instance of fragments inside the activity. Your fragment already holding a reference to the ViewModel. Delete these line from the activity -> :

viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);
viewModelRoutesFragment.init();

Make sure you initialize your fragment in activity. Your activity is just a holder block, which actually replace the fragment using fragment manager. It doenst required any viewmodel if you are using a fragment with it.

Also, call this method inside your fragment viewModelRoutesFragment.init();
below this line

 viewModelRoutesFragment = new ViewModelProvider(this).get(ViewModelRoutesFragment.class);

huangapple
  • 本文由 发表于 2020年8月23日 22:48:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63548323.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定