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
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;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.