【问题标题】:Android mvvm livedata not observingAndroid mvvm livedata 没有观察到
【发布时间】:2018-10-17 16:19:04
【问题描述】:

这是我第一次使用 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();
    }
}

【问题讨论】:

  • 请显示来自服务器和 UnknownApi 模型类的响应
  • 在 onResponse 方法中,我记录了项目的大小或数量为 3。所以我得到了响应
  • 我在问响应本身,以及你的模型类..
  • 等等!!让我登录

标签: android mvvm android-livedata


【解决方案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.
}

编辑:更多说明。

在 Activity 中,您正确地创建了一个 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();
            }
        });

    }
}

【讨论】:

  • 因为它是 mvvm 我处理模型中的 api 调用。现在我明白了。创建了 2 个不同的对象对吗?那么我如何在不创建新对象的情况下将数据发送到同一个 ViewModel 对象?\
  • API 调用不应在模型中,但您可以通过将现有 ViewModel 传递给 RetrofitHandler 的构造函数来解决此问题。
  • 那么模型是干什么用的?
  • Model 应该是从服务器返回的 API 响应。
  • 那么 api 调用是在 ViewModel 中处理的??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多