Android mvvm 实时数据未观察

Android mvvm livedata not observing

这是我第一次使用 MVVM architecture.I 我也在使用 LiveData。我只是在单击 View(MainActivity.class) 中的按钮后使用 Retrofit.So 从服务器检索数据 我调用 ViewModel class 的方法 (handleRetrofitcall()) 承担 Api 从 模型 class(Retrofit Handler.class)[=39= 调用的职责]。检索数据时模型 class 通知 ViewModel 数据(实际上是项目的大小)。我将大小设置为 LiveData 并尝试收听 it.Unfortunately 我不能't.For详细分析请看代码

型号...

改装Handler.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 回调和那里的 post 数据可能更安全。

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)。 问题是结果正在 posted 到 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();
            }
        });

    }
}