Android mvvm livedata无法观察 [英] Android mvvm livedata not observing

查看:89
本文介绍了Android mvvm livedata无法观察的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我第一次使用 MVVM 架构.我还使用 LiveData .我只是使用Retrofit从服务器检索数据,因此在单击 View(MainActivity.class)中的按钮时,我调用 ViewModel 类的方法(handleRetrofitcall())进行处理从 Model类(Retrofit Handler.class)进行Api调用的职责.Model类在检索数据时会通知ViewModel数据(实际上是项目的大小).我设置大小到LiveData并尝试收听它.不幸的是我不能.有关详细分析,请遍历代码.

This is my first time using MVVM architecture.I am also using LiveData. I simply retrieve data from server using Retrofit.So upon clicking a button in the View(MainActivity.class) I invoke the ViewModel class's method(handleRetrofitcall()) to take up the duty of Api calling from the Model class(Retrofit Handler.class).The Model class upon retrieving the data informs the ViewModel of the data(which is actually the size of items).I set the size to LiveData and try to listen for it.Unfortunately I couldn't.For detailed analysis please go through the code.

模型...

RetrofitHandler.class:

public class RetrofitHandler {
    private ApiInterface apiInterface;
    private SimpleViewModel viewModel;

    public void getData(){
        apiInterface= ApiClient.getClient().create(ApiInterface.class);
        Call<Unknownapi> call=apiInterface.doGetListResources();
        call.enqueue(new Callback<Unknownapi>() {
            @Override
            public void onResponse(Call<Unknownapi> call, Response<Unknownapi> response) {
                List<Unknownapi.Data> list;
                Unknownapi unknownapi=response.body();
                list=unknownapi.getData();
                viewModel=new SimpleViewModel();
                viewModel.postValue(list.size());
                Log.e("Size",Integer.toString(list.size()));
            }

            @Override
            public void onFailure(Call<Unknownapi> call, Throwable t) {

            }
        });
    }
}

ViewModel ....

SimpleViewModel.class:

public class SimpleViewModel extends ViewModel {
   private RetrofitHandler retrofitHandler;
   private int size;
    private MutableLiveData<Integer> mutablesize=new MutableLiveData<>();


    public SimpleViewModel() {
        super();
    }

    @Override
    protected void onCleared() {
        super.onCleared();
    }
    public void  handleRetrofitcall(){
      retrofitHandler=new RetrofitHandler();
      retrofitHandler.getData();
    }

    public void postValue(int size){
        this.size=size;
        mutablesize.postValue(this.size);
        Log.e("lk","f");

    }
    public MutableLiveData<Integer> getObject() {
        return mutablesize;
    }

}

查看.....

MainActivity.class:

public class MainActivity extends AppCompatActivity {

    private TextView status;
    private SimpleViewModel viewModel;
    private Observer<Integer> observer;
    private MutableLiveData<Integer> mutableLiveData;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        status=findViewById(R.id.status);
        viewModel=ViewModelProviders.of(MainActivity.this).get(SimpleViewModel.class);
        observer=new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer integer) {
                Log.e("lk","f");
                status.setText(Integer.toString(integer));

            }
        };
        viewModel.getObject().observe(MainActivity.this,observer);
        findViewById(R.id.retrofit).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                viewModel.handleRetrofitcall();
            }
        });

    }

    @Override
    protected void onDestroy() {
        if (observer!=null){
         viewModel.getObject().removeObserver(observer);
        }
        super.onDestroy();
    }
}

推荐答案

您正在RetrofitHandler中创建一个新的ViewModel,因此没有观察到该ViewModel.与其让RetrofitHandler内部依赖ViewModel,不如自己处理Retrofit回调并在其中发布数据,可能更安全.

You're creating a new ViewModel in the RetrofitHandler, so nothing is observing that viewmodel. Instead of having the RetrofitHandler rely on a ViewModel internally, it's probably safer to handle the Retrofit callback inself, and post data there.

public void  handleRetrofitcall(){
    retrofitHandler=new RetrofitHandler();
    retrofitHandler.getData(new Callback<List<Unknownapi.Data>> {
         // add actual callback implementation here
    ); // add a callback here, so that the data is available in the view model. Then post the results from here.
}

更多说明.

在活动"中,您正在正确创建一个ViewModel并对其进行观察(我们将其称为ViewModel A).然后,ViewModel A将创建RetrofitHandler并在该Retrofithandler上调用getData.问题是RetrofitHandler在getData中创建了一个新的ViewModel(我将其称为ViewModel B). 问题是结果正在发布到ViewModel B,没有观察到,因此似乎没有任何作用.

In the Activity, you're correctly creating a ViewModel and observing it (we'll call that ViewModel A). ViewModel A is then creating a RetrofitHandler and calling getData on that Retrofithandler. The issue is that RetrofitHandler is creating a new ViewModel in getData (which I'm going to call ViewModel B). The issue is that the results are being posted to ViewModel B, which nothing is observing, so it seems like nothing is working.

避免此问题的简便方法是确保只有一个Activity/Fragment依赖(并创建)ViewModel.没有其他关于ViewModel的信息.

Easy way to avoid this issue is to make sure that only an Activity/Fragment is relying on (and creating) ViewModels. Nothing else should know about the ViewModel.

这是一个简单的实现.我还没有测试过,但是应该或多或少是正确的.

Edit 2: Here's a simple implementation. I haven't tested it, but it should be more or less correct.

// shouldn't know anything about the view model or the view
public class RetrofitHandler { 
    private ApiInterface apiInterface;

    // this should probably pass in a different type of callback that doesn't require retrofit
    public void getData(Callback<Unknownapi> callback) {
        // only create the apiInterface once
        if (apiInterface == null) {
            apiInterface = ApiClient.getClient().create(ApiInterface.class);
        }

        // allow the calling function to handle the result
        apiInterface.doGetListResources().enqueue(callback);
    }
}

// shouldn't know how retrofit handler parses the data
public class SimpleViewModel extends ViewModel {
    private RetrofitHandler retrofitHandler = new RetrofitHandler();
    // store data in mutableSize, not with a backing field.
    private MutableLiveData<Integer> mutableSize = new MutableLiveData<>();

    public void handleRetrofitCall() {
        // handle the data parsing here
        retrofitHandler.getData(new Callback<Unknownapi>() {
            @Override
            public void onResponse(Call<Unknownapi> call, Response<Unknownapi> response) {
                Unknownapi unknownapi = response.body();
                int listSize = unknownapi.getData().size;
                // set the value of the LiveData. Observers will be notified
                mutableSize.setValue(listSize); // Note that we're using setValue because retrofit callbacks come back on the main thread.
                Log.e("Size", Integer.toString(listSize));
            }

            @Override
            public void onFailure(Call<Unknownapi> call, Throwable t) {
                // error handling should be added here
            }
        });
    }

    // this should probably return an immutable copy of the object
    public MutableLiveData<Integer> getObject() {
        return mutableSize;
    }
}

public class MainActivity extends AppCompatActivity {
    private TextView status;

    // initialize the view model only once
    private SimpleViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(SimpleViewModel.class);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        status = findViewById(R.id.status);

        // observe the view model's changes
        viewModel.getObject().observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer integer) {
                // you should handle possibility of interger being null
                Log.e("lk","f");
                status.setText(Integer.toString(integer));

            }
        });

        findViewById(R.id.retrofit).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // call the view model's function
                viewModel.handleRetrofitCall();
            }
        });

    }
}

这篇关于Android mvvm livedata无法观察的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆