无法使用Retrofit从网络服务获取数据。

huangapple go评论79阅读模式
英文:

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:

{
    &quot;ok&quot;: [
        {
            &quot;id&quot;: 1,
            &quot;username&quot;: &quot;test1&quot;,
            &quot;pass&quot;: &quot;123&quot;,
            &quot;reg_date&quot;: &quot;2020-05-20 00:00:00&quot;
        }
    ]
}

or this:

{
    &quot;error&quot;: [
        {
            &quot;message&quot;:&quot;user doesn&#39;t exists&quot;
        }
    ]
}

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(&quot;ok&quot;)
    private LiveData&lt;ArrayList&lt;POJOUsr&gt;&gt; user;
    @SerializedName(&quot;error&quot;)
    private LiveData&lt;ArrayList&lt;POJOError&gt;&gt; error;
    
    //Constructor and Getters...
}

JsonApi.java

public interface JsonApi {
    @GET(&quot;SelectAllUsr.php&quot;)
    Call&lt;LiveData&lt;POJOGenericResponse&gt;&gt; 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 = &quot;http://192.168.0.35/app_android/webservices/&quot;;
    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&lt;POJOGenericResponse&gt; genericResponse;
    private Call&lt;LiveData&lt;POJOGenericResponse&gt;&gt; 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&lt;POJOGenericResponse&gt; getGenericResponse() {
        call.clone().enqueue(new Callback&lt;LiveData&lt;POJOGenericResponse&gt;&gt;() {

            @Override
            public void onResponse(Call&lt;LiveData&lt;POJOGenericResponse&gt;&gt; call, Response&lt;LiveData&lt;POJOGenericResponse&gt;&gt; response) {
                if (response.isSuccessful()) {
                    genericResponse= response.body();
                } else {
                    //
                }
            }

            @Override
            public void onFailure(Call&lt;LiveData&lt;POJOGenericResponse&gt;&gt; call, Throwable t) {
                //
            }
        });
        return genericResponse;
    }
}

LoginViewModel.java

public class LoginViewModel extends AndroidViewModel {
    private RepositorioLogin loginRepository;
    private MutableLiveData&lt;POJOGenericResponse&gt; serverResponse;

    public ViewModelLogin(@NonNull Application application) {
        super(application);
        loginRepository = new RepositorioLogin();
        serverResponse = new MutableLiveData&lt;&gt;();
    }

    public void setServerResponse(){
        serverResponse.setValue(loginRepository.getGenericResponse().getValue());
    }

    public LiveData&lt;POJORespuestaGenerica&gt; 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&lt;POJORespuestaGenerica&gt;() {
            @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&lt;POJOGenericResponse&gt; getGenericResponse() {
        call.clone().enqueue(new Callback&lt;LiveData&lt;POJOGenericResponse&gt;&gt;() {

            @Override
            public void onResponse(Call&lt;LiveData&lt;POJOGenericResponse&gt;&gt; call, Response&lt;LiveData&lt;POJOGenericResponse&gt;&gt; response) {
                if (response.isSuccessful()) {
                    genericResponse= response.body();
                } else {
                    //
                }
            }

            @Override
            public void onFailure(Call&lt;LiveData&lt;POJOGenericResponse&gt;&gt; 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&lt;POJOGenericResponse&gt; genericResponse;

huangapple
  • 本文由 发表于 2020年5月30日 03:47:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/62093624.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定