[英]Android MVVM architecture and observing changes on data from an API
我是 Android MVVM 架構的新手。 我有一個本地運行的 API,其中包含數據(“交易”)。 我只想向 API 發出請求並在文本字段中顯示該數據。 目前,首次加載片段時數據不會顯示,但如果我轉到另一個活動,然后返回到它加載的片段。
這里有 3 類重要性。
儀表板視圖模型.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;
}
}
儀表板片段.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
的變化嗎?
我認為這會有所幫助。 在網絡調用的 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;
}
}
由於每當調用 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
在函數中的存儲庫類中獲取交易。 您正在初始化實時數據。 在后台線程中請求 url 並在尚未從服務器接收到的實時數據上發布值。
要解決此問題,請在存儲庫的構造函數中創建實時數據實例,並在 onResponse 回調中在實時數據上創建后值。
//抱歉寫得不好,從手機上發布。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.