Ответ Android MVVM и модифицированного api равен нулю

#android #mvvm #retrofit #android-room #android-databinding

#Android #mvvm #модифицированный #android-комната #android-привязка к данным

Вопрос:

Эта функция используется для входа пользователя в систему. Я использую привязку данных и RxJava

 public void loginUser(String idNumber, String password) {
    RetrofitService.getApiService()
            .agentLogin(new LoginRequest(idNumber, password))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Response<LoginResponse>>() {
                @Override
                public void call(Response<LoginResponse> userResponse) {
                    if (userResponse.isSuccessful() ) {
                        executor.execute(new Runnable() {
                            @Override
                            public void run() {

                                Log.i("AUTHKEY",userResponse.body().getUser().getAuthKey());
                                userDao.insert(userResponse.body().getUser());
                            }
                        });
                    }
                }
            });

}
  

При входе в систему происходит сбой приложения Log.i("AUTHKEY",userResponse.body().getUser().getAuthKey());

Ошибка java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Integer com.vuna.agent.model.LoginResponse$User.getId()' on a null object reference

Из регистратора Okhttp сервер возвращает правильный ответ

 2019-04-12 12:33:36.707 28896-29064/com.vuna.agent D/OkHttp: <-- 200 OK http://example.com/login (923ms)

2019-04-12 12:33:36.709 28896-29064/com.vuna.agent D/OkHttp: {"code":201,"message":"You are now logged in!","id":2,"firstname":"Victor","lastname":"Amwollo","authkey":"22sA1JvVo4hmzhps1NVIO7_B6f4yCp_e"}
2019-04-12 12:33:36.709 28896-29064/com.vuna.agent D/OkHttp: <-- END HTTP (141-byte body)
  

Вот класс LoginResponse с внутренним классом сущности

 public class LoginResponse {

    private Boolean success;

    private User user;


    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }


    @Entity(tableName = "user")
    public static class User {

        @PrimaryKey(autoGenerate = true)
        @SerializedName("id")
        private Integer id;

        private String firstName;
        private String lastName;

        private String authKey;

        //getters and setters

    }
}
  

Почему я получаю сообщение об ошибке?

Комментарии:

1. не могли бы вы опубликовать LoginResponse класс?

2. ResponseBody может быть использован один раз из ответа, и именно поэтому он выдает NullPointerException . Попробуйте сохранить его в локальной переменной и использовать больше из этой переменной.

3. @Dhaiyur, я обновил код, пожалуйста, проверьте

Ответ №1:

response.body() Метод в ответе считывает входной (сетевой) поток и преобразует его в строку. Таким образом, он динамически создает строку и возвращает ее вам. Во второй раз, когда вы его вызываете, сетевой поток уже израсходован и больше недоступен.

Итак, решение состоит в том, чтобы сохранить результат ответа в переменной, а затем обращаться к нему столько раз, сколько необходимо.

Ознакомьтесь с приведенным ниже кодом:

 @Override
public void call(Response<LoginResponse> userResponse) {
    if (userResponse.isSuccessful() ) {
        LoginResponse data = userResponse.body(); // Consume response body once and then use it in this method further
        executor.execute(new Runnable() {
            @Override
            public void run() {
                Log.i("AUTHKEY", data.getUser().getAuthKey()); // access data variable here
                userDao.insert(data.getUser()); // access data variable here
            }
        });
    }
}
  

Комментарии:

1. Это верно только в том случае, если вы добавляете @Streaming в свой метод модифицированного интерфейса, в противном случае подключение к сети выполняется на этом этапе 🙂

2. Да, @StuartCampbell, вы правы. Я опубликовал свой ответ с первоначальным замечанием, что это может быть так.

Ответ №2:

Вы получаете нулевой указатель, потому что ваш json не сопоставляется с LoginResponse .

попробуйте

 public class LoginResponse {

    private Boolean success;
    private Integer id;
    private String firstName;
    private String lastName;
    private String authKey;

}
  

Я очистил ваш RX. Примечание: скобки могут быть неправильными, поскольку я привык к kotlin.

 public void loginUser(String idNumber, String password) {
    RetrofitService.getApiService()
        .agentLogin(new LoginRequest(idNumber, password))
        .filter { it.isSuccessful(); }
        .map { it.body(); }
        .map { new User(it.getId()...) /* covert LoginResponse to User here */ } 
        .flatMapCompletable { Completable.fromAction { userDao.insert(it); } }
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe();                                 
}