Retrofit 完成下载我的数据并更新 HashMap 后,MutableLiveData 没有 return HashMap 对象
MutableLiveData doesn't return HashMap object after Retrofit finishes downloading my data and updating the HashMap
所以,我最近学习了 Retrofit,并试图创建一个使用 API 来下载 Pokemon 详细信息的应用程序。这是 MainActivity.java class 和 MainActivityViewModel.java class 的代码。还有其他 classes,但它们主要是模型 classes,所以我没有提到它们:
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.widget.Toast;
import com.arpansircar.java.pokemonapplication.R;
import com.arpansircar.java.pokemonapplication.viewmodel.MainActivityViewModel;
public class MainActivity extends AppCompatActivity {
private MainActivityViewModel mainActivityViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
}
@Override
protected void onResume() {
super.onResume();
observeRetrofitFailures();
mainActivityViewModel.downloadMainPokemonData();
mainActivityViewModel.returnMainDownloadedData().observe(this, resultsPokemonServiceModels ->
mainActivityViewModel.downloadSelectedPokemonData(resultsPokemonServiceModels));
mainActivityViewModel.returnDownloadedPokemonData().observe(this, map -> {
});
}
private void observeRetrofitFailures() {
mainActivityViewModel.returnMainServiceErrorLiveData().observe(this, s ->
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show());
mainActivityViewModel.returnSelectedPokemonServiceErrorLiveData().observe(this, s ->
Toast.makeText(this, s, Toast.LENGTH_SHORT).show());
}
}
MainActivityViewModel.java
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.arpansircar.java.pokemonapplication.model.GetPokemonId;
import com.arpansircar.java.pokemonapplication.model.MainPokemonServiceModel;
import com.arpansircar.java.pokemonapplication.model.ResultsPokemonServiceModel;
import com.arpansircar.java.pokemonapplication.model.SelectedPokemonModel;
import com.arpansircar.java.pokemonapplication.retrofit.MainPokemonRetrofitInstance;
import com.arpansircar.java.pokemonapplication.retrofit.PokemonServiceInterface;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.internal.EverythingIsNonNull;
public class MainActivityViewModel extends ViewModel {
private MainPokemonServiceModel mainPokemonServiceModel;
private final Map<String, String> pokemonHashMap = new HashMap<>();
private final PokemonServiceInterface mainPokemonServiceInterface = MainPokemonRetrofitInstance.getInstance();
private final MutableLiveData<String> mainServiceErrorLiveData = new MutableLiveData<>();
private final MutableLiveData<String> selectedPokemonServiceErrorLiveData = new MutableLiveData<>();
private final MutableLiveData<Map<String, String>> downloadMainPokemonData = new MutableLiveData<>();
private final MutableLiveData<List<ResultsPokemonServiceModel>> resultsPokemonServiceModelListLiveData = new MutableLiveData<>();
public void downloadMainPokemonData() {
Call<MainPokemonServiceModel> mainPokemonServiceModelCall = mainPokemonServiceInterface.getResultsDataFromService();
mainPokemonServiceModelCall.enqueue(new Callback<MainPokemonServiceModel>() {
@Override
@EverythingIsNonNull
public void onResponse(Call<MainPokemonServiceModel> call, Response<MainPokemonServiceModel> response) {
if (!response.isSuccessful()) {
mainServiceErrorLiveData.postValue(String.valueOf(response.code()));
return;
}
mainPokemonServiceModel = response.body();
resultsPokemonServiceModelListLiveData.postValue(Objects.requireNonNull(mainPokemonServiceModel).resultsPokemonServiceModel);
}
@Override
@EverythingIsNonNull
public void onFailure(Call<MainPokemonServiceModel> call, Throwable t) {
mainServiceErrorLiveData.postValue(t.getMessage());
}
});
}
public void downloadSelectedPokemonData(List<ResultsPokemonServiceModel> resultsPokemonServiceModelList) {
for (ResultsPokemonServiceModel resultsPokemonServiceModel : resultsPokemonServiceModelList) {
String pokemonId = GetPokemonId.getId(resultsPokemonServiceModel.url);
Call<SelectedPokemonModel> selectedPokemonModelCall = MainPokemonRetrofitInstance.getInstance().getSelectedPokemonSprite(pokemonId);
selectedPokemonModelCall.enqueue(new Callback<SelectedPokemonModel>() {
@Override
@EverythingIsNonNull
public void onResponse(Call<SelectedPokemonModel> call, Response<SelectedPokemonModel> response) {
if (!response.isSuccessful()) {
selectedPokemonServiceErrorLiveData.postValue(String.valueOf(response.code()));
return;
}
SelectedPokemonModel selectedPokemonModel = response.body();
String pokemonName = Objects.requireNonNull(selectedPokemonModel).pokemonName;
String pokemonSpriteUrl = selectedPokemonModel.pokemonSpriteModel.spriteUrl;
pokemonHashMap.put(pokemonName, pokemonSpriteUrl);
}
@Override
@EverythingIsNonNull
public void onFailure(Call<SelectedPokemonModel> call, Throwable t) {
selectedPokemonServiceErrorLiveData.postValue(t.getMessage());
}
});
}
downloadMainPokemonData.postValue(pokemonHashMap);
}
public LiveData<Map<String, String>> returnDownloadedPokemonData() {
return downloadMainPokemonData;
}
public LiveData<List<ResultsPokemonServiceModel>> returnMainDownloadedData() {
return resultsPokemonServiceModelListLiveData;
}
public LiveData<String> returnMainServiceErrorLiveData() {
return mainServiceErrorLiveData;
}
public LiveData<String> returnSelectedPokemonServiceErrorLiveData() {
return selectedPokemonServiceErrorLiveData;
}
}
我的主要问题在 downloadMainPokemonData.postValue(pokemonHashMap);
行。下载完成后,MutableLiveData 对象(出于某种原因)不会收到关于此的通知,即 HashMap 不会 return 返回 MainActivity。
我进行了一些日志检查,发现该方法确实被触发了。然而,系统甚至在下载完成之前就退出该方法。下载确实完成了,是的。但是由于某些原因,它不会 return 将下载的 HashMap 返回到 MainActivity。我认为这可能是因为 Retrofit 提供的入队方法是异步的,并且在后台线程中完成所有任务。
有人可以提供任何关于我如何解决这个问题的提示吗?谢谢!
selectedPokemonModelCall.enqueue
是异步请求。 downloadMainPokemonData.postValue(pokemonHashMap)
在处理 Response<SelectedPokemonModel>
数据之前调用
所以,我最近学习了 Retrofit,并试图创建一个使用 API 来下载 Pokemon 详细信息的应用程序。这是 MainActivity.java class 和 MainActivityViewModel.java class 的代码。还有其他 classes,但它们主要是模型 classes,所以我没有提到它们:
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.widget.Toast;
import com.arpansircar.java.pokemonapplication.R;
import com.arpansircar.java.pokemonapplication.viewmodel.MainActivityViewModel;
public class MainActivity extends AppCompatActivity {
private MainActivityViewModel mainActivityViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
}
@Override
protected void onResume() {
super.onResume();
observeRetrofitFailures();
mainActivityViewModel.downloadMainPokemonData();
mainActivityViewModel.returnMainDownloadedData().observe(this, resultsPokemonServiceModels ->
mainActivityViewModel.downloadSelectedPokemonData(resultsPokemonServiceModels));
mainActivityViewModel.returnDownloadedPokemonData().observe(this, map -> {
});
}
private void observeRetrofitFailures() {
mainActivityViewModel.returnMainServiceErrorLiveData().observe(this, s ->
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show());
mainActivityViewModel.returnSelectedPokemonServiceErrorLiveData().observe(this, s ->
Toast.makeText(this, s, Toast.LENGTH_SHORT).show());
}
}
MainActivityViewModel.java
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.arpansircar.java.pokemonapplication.model.GetPokemonId;
import com.arpansircar.java.pokemonapplication.model.MainPokemonServiceModel;
import com.arpansircar.java.pokemonapplication.model.ResultsPokemonServiceModel;
import com.arpansircar.java.pokemonapplication.model.SelectedPokemonModel;
import com.arpansircar.java.pokemonapplication.retrofit.MainPokemonRetrofitInstance;
import com.arpansircar.java.pokemonapplication.retrofit.PokemonServiceInterface;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.internal.EverythingIsNonNull;
public class MainActivityViewModel extends ViewModel {
private MainPokemonServiceModel mainPokemonServiceModel;
private final Map<String, String> pokemonHashMap = new HashMap<>();
private final PokemonServiceInterface mainPokemonServiceInterface = MainPokemonRetrofitInstance.getInstance();
private final MutableLiveData<String> mainServiceErrorLiveData = new MutableLiveData<>();
private final MutableLiveData<String> selectedPokemonServiceErrorLiveData = new MutableLiveData<>();
private final MutableLiveData<Map<String, String>> downloadMainPokemonData = new MutableLiveData<>();
private final MutableLiveData<List<ResultsPokemonServiceModel>> resultsPokemonServiceModelListLiveData = new MutableLiveData<>();
public void downloadMainPokemonData() {
Call<MainPokemonServiceModel> mainPokemonServiceModelCall = mainPokemonServiceInterface.getResultsDataFromService();
mainPokemonServiceModelCall.enqueue(new Callback<MainPokemonServiceModel>() {
@Override
@EverythingIsNonNull
public void onResponse(Call<MainPokemonServiceModel> call, Response<MainPokemonServiceModel> response) {
if (!response.isSuccessful()) {
mainServiceErrorLiveData.postValue(String.valueOf(response.code()));
return;
}
mainPokemonServiceModel = response.body();
resultsPokemonServiceModelListLiveData.postValue(Objects.requireNonNull(mainPokemonServiceModel).resultsPokemonServiceModel);
}
@Override
@EverythingIsNonNull
public void onFailure(Call<MainPokemonServiceModel> call, Throwable t) {
mainServiceErrorLiveData.postValue(t.getMessage());
}
});
}
public void downloadSelectedPokemonData(List<ResultsPokemonServiceModel> resultsPokemonServiceModelList) {
for (ResultsPokemonServiceModel resultsPokemonServiceModel : resultsPokemonServiceModelList) {
String pokemonId = GetPokemonId.getId(resultsPokemonServiceModel.url);
Call<SelectedPokemonModel> selectedPokemonModelCall = MainPokemonRetrofitInstance.getInstance().getSelectedPokemonSprite(pokemonId);
selectedPokemonModelCall.enqueue(new Callback<SelectedPokemonModel>() {
@Override
@EverythingIsNonNull
public void onResponse(Call<SelectedPokemonModel> call, Response<SelectedPokemonModel> response) {
if (!response.isSuccessful()) {
selectedPokemonServiceErrorLiveData.postValue(String.valueOf(response.code()));
return;
}
SelectedPokemonModel selectedPokemonModel = response.body();
String pokemonName = Objects.requireNonNull(selectedPokemonModel).pokemonName;
String pokemonSpriteUrl = selectedPokemonModel.pokemonSpriteModel.spriteUrl;
pokemonHashMap.put(pokemonName, pokemonSpriteUrl);
}
@Override
@EverythingIsNonNull
public void onFailure(Call<SelectedPokemonModel> call, Throwable t) {
selectedPokemonServiceErrorLiveData.postValue(t.getMessage());
}
});
}
downloadMainPokemonData.postValue(pokemonHashMap);
}
public LiveData<Map<String, String>> returnDownloadedPokemonData() {
return downloadMainPokemonData;
}
public LiveData<List<ResultsPokemonServiceModel>> returnMainDownloadedData() {
return resultsPokemonServiceModelListLiveData;
}
public LiveData<String> returnMainServiceErrorLiveData() {
return mainServiceErrorLiveData;
}
public LiveData<String> returnSelectedPokemonServiceErrorLiveData() {
return selectedPokemonServiceErrorLiveData;
}
}
我的主要问题在 downloadMainPokemonData.postValue(pokemonHashMap);
行。下载完成后,MutableLiveData 对象(出于某种原因)不会收到关于此的通知,即 HashMap 不会 return 返回 MainActivity。
我进行了一些日志检查,发现该方法确实被触发了。然而,系统甚至在下载完成之前就退出该方法。下载确实完成了,是的。但是由于某些原因,它不会 return 将下载的 HashMap 返回到 MainActivity。我认为这可能是因为 Retrofit 提供的入队方法是异步的,并且在后台线程中完成所有任务。
有人可以提供任何关于我如何解决这个问题的提示吗?谢谢!
selectedPokemonModelCall.enqueue
是异步请求。 downloadMainPokemonData.postValue(pokemonHashMap)
在处理 Response<SelectedPokemonModel>
数据之前调用