Android MVVM体系结构并观察API中数据的变化

问题描述 投票:0回答:3

我是Android MVVM架构的新手。我有一个本地运行的API,其中包含数据(“交易”)。我只想向API发出请求,然后在文本字段中显示该数据。当前,当第一次加载该片段时,数据没有显示,但是如果我转到另一个活动然后又返回到该片段,它将加载。

这里有3个重要类别。

DashboardViewModel.java:

package com.example.android_client.ui.dashboard;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.example.android_client.models.Deal;
import com.example.android_client.repository.Repository;

import java.util.List;

public class DashboardViewModel extends ViewModel {

    private MutableLiveData<String> mText;
    private Repository repository;
    private MutableLiveData<List<Deal>> deals = null;

    public void init() {
        if(this.deals == null) {
            this.repository = Repository.getInstance();
            this.deals = this.repository.getDeals();
        }
    }

    public DashboardViewModel() {
        this.mText = new MutableLiveData<>();
    }

    public LiveData<List<Deal>> getDeals() {
        return this.deals;
    }
}

DashboardFragment.java:

package com.example.android_client.ui.dashboard;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

import com.example.android_client.R;
import com.example.android_client.models.Deal;

import java.util.List;

public class DashboardFragment extends Fragment {

    private DashboardViewModel dashboardViewModel;

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
        final TextView textView = root.findViewById(R.id.text_dashboard);
        dashboardViewModel = ViewModelProviders.of(this).get(DashboardViewModel.class);
        dashboardViewModel.init();
        dashboardViewModel.getDeals().observe(this, new Observer<List<Deal>>() {
            @Override
            public void onChanged(List<Deal> deals) {
                if (deals != null && !deals.isEmpty()) {
                    System.out.println(deals.get(0).toString());
                    textView.setText(deals.get(0).toString());
                }
            }
        });
        return root;
    }
}

和Repository.java:

package com.example.android_client.repository;

import androidx.lifecycle.MutableLiveData;

import com.example.android_client.models.Deal;
import com.google.gson.Gson;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class Repository {

    private static Repository instance;
    private ArrayList<Deal> dealsList = new ArrayList<>();
    private final OkHttpClient client = new OkHttpClient();

    public static Repository getInstance() {
        if(instance == null) {
            instance = new Repository();
        }
        return instance;
    }

    private Repository() {}

    public MutableLiveData<List<Deal>> getDeals() {
        setDeals();
        MutableLiveData<List<Deal>> deals = new MutableLiveData<>();
        deals.setValue(dealsList);
        return deals;
    }

    private void setDeals() {
        Request request = new Request.Builder()
                .url("http://10.0.2.2:8000/api/deals?<params here>")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                try (ResponseBody responseBody = response.body()) {
                    if (!response.isSuccessful()) {
                        throw new IOException("Unexpected code " + response);
                    }
                    String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException
                    Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class);
                    dealsList = new ArrayList<>(Arrays.asList(deals));
                }
            }
        });

    }
}

[单步浏览Repository类中的代码时,我看到加载片段时调用了setDeals(),并且回调中的请求已排队。第一次返回getDeals()时,它将返回0个交易的列表(在MutableLiveData对象中)。

除非片段已加载,否则回调中的[onResponse不会运行。调试时,我可以看到数据在对象中(所有Gson东西都可以正常工作),但是onChanged不再被调用(它设置了文本视图)。

我是否无法正确观察deals上的更改?

java android mvvm okhttp android-mvvm
3个回答
0
投票
在您的存储库类中的函数中获取交易。您正在初始化实时数据。在后台线程中请求url,并在尚未从服务器接收到的实时数据上发布值。

要解决此问题,请在存储库的构造函数中创建livedata实例,并在onResponse回调中的livedata上添加postvalue。

//对不起,写不对,发自手机。


0
投票
我认为这会有所帮助。在网络调用的onResponse中尝试对MutableLiveData进行postValue。请按如下所示更改您的存储库类:

package com.example.android_client.repository; import androidx.lifecycle.MutableLiveData; import com.example.android_client.models.Deal; import com.google.gson.Gson; import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; public class Repository { private static Repository instance; private ArrayList<Deal> dealsList = new ArrayList<>(); private final OkHttpClient client = new OkHttpClient(); MutableLiveData<List<Deal>> deals = new MutableLiveData<>(); public static Repository getInstance() { if(instance == null) { instance = new Repository(); } return instance; } private Repository() {} private MutableLiveData<List<Deal>> getDeals() { Request request = new Request.Builder() .url("http://10.0.2.2:8000/api/deals?<params here>") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) { throw new IOException("Unexpected code " + response); } String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class); dealsList = new ArrayList<>(Arrays.asList(deals)); deals.postValue(dealsList); } } }); return deals; } }


0
投票
由于调用getDeals()并将api响应值通知其他实时数据实例时将创建新的实时数据实例,因此您的代码无法正常工作。您必须将api响应值设置为getDeals()返回的MutableLiveData的相同实例。

我并不是说这是最好的体系结构解决方案,但是如果您将可变的实时数据作为类属性创建并在调用getDeals()时将其返回。可能会起作用。

此外,一个好的做法是返回一个LiveData而不是MutableLiveData,以不允许外部组件修改内部值。

请看下面的代码。

OBS:也许有些语法错误,因为我还没有编译它

import com.example.android_client.models.Deal; import com.google.gson.Gson; import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; public class Repository { private static Repository instance; private ArrayList<Deal> dealsList = new ArrayList<>(); private final OkHttpClient client = new OkHttpClient(); private MutableLiveData<List<Deal>> _deals = new MutableLiveData<>(); private LiveData<List<Deal>> deals = _deals public static Repository getInstance() { if(instance == null) { instance = new Repository(); } return instance; } private Repository() {} public LiveData<List<Deal>> getDeals() { setDeals(); return deals; } private void setDeals() { Request request = new Request.Builder() .url("http://10.0.2.2:8000/api/deals?<params here>") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) { throw new IOException("Unexpected code " + response); } String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class); dealsList = new ArrayList<>(Arrays.asList(deals)); _deals.setValue(dealsList); } } }); } } When

© www.soinside.com 2019 - 2024. All rights reserved.