#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();
}