Android mvvm livedata无法观察

时间:2018-10-17 16:19:04

标签: android mvvm android-livedata

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

模型...

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();
    }
}

1 个答案:

答案 0 :(得分:1)

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

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,没有观察到,因此似乎没有任何作用。

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

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

// 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();
            }
        });

    }
}