英文:
Unable to fetch data from webservice with Retrofit
问题
以下是翻译好的内容:
JSON 响应:这可以是以下两者之一:
{
"ok": [
{
"id": 1,
"username": "test1",
"pass": "123",
"reg_date": "2020-05-20 00:00:00"
}
]
}
或者这个:
{
"error": [
{
"message": "用户不存在"
}
]
}
POJOGenericResponse.java
public class POJOGenericResponse {
@SerializedName("ok")
private LiveData<ArrayList<POJOUser>> user;
@SerializedName("error")
private LiveData<ArrayList<POJOError>> error;
// 构造函数和Getter方法...
}
JsonApi.java
public interface JsonApi {
@GET("SelectAllUsr.php")
Call<LiveData<POJOGenericResponse>> getGenericResponse();
}
RetrofitInstance.java
public class RetrofitInstance {
private static String BASE_URL = "http://192.168.0.35/app_android/webservices/";
private static Retrofit retrofit;
private static Gson gson;
public Retrofit getRetrofitInstance() {
gson = new GsonBuilder().setLenient().create();
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
LoginRepository.java
public class LoginRepository {
private RetrofitInstance retrofitInstance;
private JsonApi jsonApi;
private LiveData<POJOGenericResponse> genericResponse;
private Call<LiveData<POJOGenericResponse>> call;
public LoginRepository() {
retrofitInstance = new RetrofitInstance();
jsonApi = retrofitInstance.getRetrofitInstance().create(JsonApi.class);
call = jsonApi.getGenericResponse();
}
// TODO: 这应该在另一个类中完成吗?
public LiveData<POJOGenericResponse> getGenericResponse() {
call.clone().enqueue(new Callback<LiveData<POJOGenericResponse>>() {
@Override
public void onResponse(Call<LiveData<POJOGenericResponse>> call, Response<LiveData<POJOGenericResponse>> response) {
if (response.isSuccessful()) {
genericResponse = response.body();
} else {
//
}
}
@Override
public void onFailure(Call<LiveData<POJOGenericResponse>> call, Throwable t) {
//
}
});
return genericResponse;
}
}
LoginViewModel.java
public class LoginViewModel extends AndroidViewModel {
private LoginRepository loginRepository;
private MutableLiveData<POJOGenericResponse> serverResponse;
public LoginViewModel(@NonNull Application application) {
super(application);
loginRepository = new LoginRepository();
serverResponse = new MutableLiveData<>();
}
public void setServerResponse() {
serverResponse.setValue(loginRepository.getGenericResponse().getValue());
}
public LiveData<POJOGenericResponse> getServerResponse() {
return serverResponse;
}
}
FragmentData.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_data, container, false);
TextView exampleText = v.findViewById(R.id.tv_test);
LoginViewModel loginViewModel = new ViewModelProvider(requireActivity()).get(LoginViewModel.class);
loginViewModel.getServerResponse().observe(requireActivity(), new Observer<POJOGenericResponse>() {
@Override
public void onChanged(POJOGenericResponse pojoGenericResponse) {
if (pojoGenericResponse.getUser() != null) {
exampleText.setText(pojoGenericResponse.getUser().getValue().get(0).getUsername());
}
if (pojoGenericResponse.getError() != null) {
exampleText.setText(pojoGenericResponse.getError().getValue().get(0).getMessage());
}
}
});
}
调试时出现的错误是:
>response = 无法找到局部变量'response' serverResponse.setValue(loginRepository.getGenericResponse().getValue());\n = java.lang.NullPointerException
response = 无法找到局部变量'response'
描述了问题本身,但无法解决它。
对于MVVM
架构的实现,欢迎提供任何建议。
在此之前,非常感谢。
英文:
I'm trying to load some very simple data in JSON format, generated by a webservice, using Retrofit
and Gson
and also trying to implement MVVM
architecture, but I'm getting a null
value when calling data from ViewModel
:
I've seen many SO questions (or maybe not so many) but can't figure out where and why I'm getting this problems.
So, what I have is this
JSON RESPONSE: This could be either this one:
{
"ok": [
{
"id": 1,
"username": "test1",
"pass": "123",
"reg_date": "2020-05-20 00:00:00"
}
]
}
or this:
{
"error": [
{
"message":"user doesn't exists"
}
]
}
I've created the correspondign POJOs for each response type, which I'll omit for simplicity. But also I've created a generic POJO for handling the response (thanks to @Công Hải, )
*POJOGenericResponse.java
public class POJOGenericResponse{
@SerializedName("ok")
private LiveData<ArrayList<POJOUsr>> user;
@SerializedName("error")
private LiveData<ArrayList<POJOError>> error;
//Constructor and Getters...
}
JsonApi.java
public interface JsonApi {
@GET("SelectAllUsr.php")
Call<LiveData<POJOGenericResponse>> getGenericResponse();
}
I don't know how this class should be called, according to its purpose and name conventions
RetrofitInstance.java
public class RetrofitInstance {
private static String URL_BASE = "http://192.168.0.35/app_android/webservices/";
private static Retrofit retrofit;
private static Gson gson;
public Retrofit getRetrofitInstance(){
gson = new GsonBuilder().setLenient().create();
if(retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(URL_BASE)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
LoginRepository.java
public class LoginRepository{
private RetrofitInstance retrofitInstance;
private JsonApi jsonApi;
private LiveData<POJOGenericResponse> genericResponse;
private Call<LiveData<POJOGenericResponse>> call;
public LoginRepository() {
retrofitInstance = new RetrofitInstance();
jsonApi = retrofitInstance.getRetrofitInstance().create(JsonApi.class);
call = jsonApi.getRespuestaGenerica();
}
//TODO: This should be done in another class??
public LiveData<POJOGenericResponse> getGenericResponse() {
call.clone().enqueue(new Callback<LiveData<POJOGenericResponse>>() {
@Override
public void onResponse(Call<LiveData<POJOGenericResponse>> call, Response<LiveData<POJOGenericResponse>> response) {
if (response.isSuccessful()) {
genericResponse= response.body();
} else {
//
}
}
@Override
public void onFailure(Call<LiveData<POJOGenericResponse>> call, Throwable t) {
//
}
});
return genericResponse;
}
}
LoginViewModel.java
public class LoginViewModel extends AndroidViewModel {
private RepositorioLogin loginRepository;
private MutableLiveData<POJOGenericResponse> serverResponse;
public ViewModelLogin(@NonNull Application application) {
super(application);
loginRepository = new RepositorioLogin();
serverResponse = new MutableLiveData<>();
}
public void setServerResponse(){
serverResponse.setValue(loginRepository.getGenericResponse().getValue());
}
public LiveData<POJORespuestaGenerica> getServerResponse(){
return serverResponse;
}
}
Here's where the data should be shown
FragmentData.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_data, container, false);
TextView exampleText = v.findViewById(R.id.tv_test);
LoginViewModel loginViewModel = new ViewModelProvider(requireActivity()).get(LoginViewModel.class);
loginViewModel.getServerResponse().observe(requireActivity(), new Observer<POJORespuestaGenerica>() {
@Override
public void onChanged(POJOGenericResponse pojoGenericResponse) {
if (pojoGenericResponse.getUser() != null) {
exampleText.setText(pojoGenericResponse.getUser().getValue().get(0).getUsername());
}
if (pojoGenericResponse.getError() != null) {
exampleText.setText(pojoGenericResponse.getError().getValue().get(0).getMensaje());
}
}
});
When debugging, the error that I get is
>response = Cannot find local variable 'response' serverResponse.setValue(loginRepository.getGenericResponse().getValue());\n = java.lang.NullPointerException
response = Cannot find local variable 'response'
which describe the problem by itself, but can't manage to solve it.
Also, any recommendation on the implementation of the MVVM
architecture will be very appreciated.
Beforehand, thank you very much
答案1
得分: 1
看起来这是一个不正确的位 --
public void getGenericResponse() {
call.clone().enqueue(new Callback<LiveData<POJOGenericResponse>>() {
@Override
public void onResponse(Call<LiveData<POJOGenericResponse>> call, Response<LiveData<POJOGenericResponse>> response) {
if (response.isSuccessful()) {
genericResponse = response.body();
} else {
//
}
}
@Override
public void onFailure(Call<LiveData<POJOGenericResponse>> call, Throwable t) {
//
}
});
}
所以onResponse
是一个异步调用,你正从方法中立即返回return genericResponse;
。
与其从这个方法获得一个返回值,将其更改为void
,然后直接在private LiveData<POJOGenericResponse> genericResponse;
上进行观察。
英文:
Looks like this is an incorrect bit --
public LiveData<POJOGenericResponse> getGenericResponse() {
call.clone().enqueue(new Callback<LiveData<POJOGenericResponse>>() {
@Override
public void onResponse(Call<LiveData<POJOGenericResponse>> call, Response<LiveData<POJOGenericResponse>> response) {
if (response.isSuccessful()) {
genericResponse= response.body();
} else {
//
}
}
@Override
public void onFailure(Call<LiveData<POJOGenericResponse>> call, Throwable t) {
//
}
});
return genericResponse;
}
So onResponse
is an asynchronous call and you are returning the return genericResponse;
immediately from the method.
Rather than getting a return from this method change it to void and directly observe on private LiveData<POJOGenericResponse> genericResponse;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论