使用 Retrofit 我想从 JSON 响应中访问 userId(来自对象内部数组的值)
Using Retrofit i want to access the userId from the JSON Response (a value from an array inside object)
我是第一次使用Retrofit。所以请不要介意愚蠢。
我有 2 个问题:
问题 1. 如何从 API JSON 响应中获取键“userId”的值。 (当 isSuccessful 为真时)以下是来自 API.
的响应
我可以从下面乱七八糟的代码中得到userId,请教我一个更好的方法:
JSONObject jsonObject = new JSONObject(new Gson().toJson(response.body()));
JSONArray userInfoObject = jsonObject.getJSONArray("userInfo");
JSONObject userIDObject = userInfoObject.getJSONObject(0);
Long userId = userIDObject.getLong("userId");
问题二:
onResponse 当 isSuccessful 为假时,response.body 显示为空。那么在这种情况下我如何访问 API JSON 响应。但是,在使用 Okhttp 日志记录时,我发现在这种情况下 okhttp 也会记录响应,但是 Retrofit 回调显示 response.body() 为空。
界面Class
public interface UserInfoClient {
@Headers("x-st-diagnostics-callerid: DKAPP-RETROFIT")
@POST("/api/User/")
Call<UserInfoModel> createUser(
@Header("x-st-diagnostics-correlationid") String uniqueID,
@Body UserInfoModel userInfo);
}
DataModel
public class UserInfoModel {
private List userInfo;
private String statusMessage;
private Integer statusCode;
private Long userId;
private String userFullName, userPassword, userName, userEmail, userMobileNumber, userWebsite, userDateOfBirth, userProfileText, userProfileDisplayPhoto, userProfileCoverPhoto;
public UserInfoModel(Long userId, String userFullName, String userPassword, String userName, String userEmail, String userMobileNumber, String userWebsite, String userDateOfBirth, String userProfileText, String userProfileDisplayPhoto, String userProfileCoverPhoto) {
this.userId = userId;
this.userFullName = userFullName;
this.userPassword = userPassword;
this.userName = userName;
this.userEmail = userEmail;
this.userMobileNumber = userMobileNumber;
this.userWebsite = userWebsite;
this.userDateOfBirth = userDateOfBirth;
this.userProfileText = userProfileText;
this.userProfileDisplayPhoto = userProfileDisplayPhoto;
this.userProfileCoverPhoto = userProfileCoverPhoto;
}
public Long getUserId() {
return userId;
}
public List getUserInfo() {
return userInfo;
}
public Integer getStatusCode() {
return statusCode;
}
public String getStatusMessage() {
return statusMessage;
}
}
Activity.java
public class ActivityUserInfo extends AppCompatActivity {
private static final String TAG = "ActivityUserInfo";
private EditText etUserId, etFullName, etPassword, etUsername, etEmail, etMobileNumber, etWebsite, etDob, etProfileTxt, etDispPhoto, etCoverPhoto;
private Button btnUpload;
public static Retrofit retrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate: begins");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_info);
etUserId = findViewById(R.id.et_userID);
etFullName = findViewById(R.id.et_fullName);
etPassword = findViewById(R.id.et_password);
etUsername = findViewById(R.id.et_username);
etEmail = findViewById(R.id.et_email);
etMobileNumber = findViewById(R.id.et_mobileNumber);
etWebsite = findViewById(R.id.et_website);
etDob = findViewById(R.id.et_dob);
etProfileTxt = findViewById(R.id.et_profileBio);
etDispPhoto = findViewById(R.id.et_profilePhoto);
etCoverPhoto = findViewById(R.id.et_coverPhoto);
btnUpload = findViewById(R.id.btn_uploadUserInfo);
btnUpload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
UserInfoModel userInfo = new UserInfoModel(
Long.parseLong(etUserId.getText().toString()),
etFullName.getText().toString(),
etPassword.getText().toString(),
etUsername.getText().toString(),
etEmail.getText().toString(),
etMobileNumber.getText().toString(),
etWebsite.getText().toString(),
etDob.getText().toString(),
etProfileTxt.getText().toString(),
etDispPhoto.getText().toString(),
etCoverPhoto.getText().toString()
);
sendNetworkRequest(userInfo);
}
});
}
private void sendNetworkRequest(UserInfoModel userInfo){
Log.d(TAG, "sendNetworkRequest: begins");
//Create okhttp client
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
//Adding logging interceptor tot he okHttp client
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
//set logging interceptor properties
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
//To redact a header from logging
logging.redactHeader("Content-Type");
//Disable logging interceptor in mode other than DEBUG.
if (BuildConfig.DEBUG) {
//Adding logging interceptor to the okHttpClient using okHttp client builder (conditional for debug only)
okHttpClientBuilder.addInterceptor(logging);
}
//Create Retrofit Instance
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://abc.ett.io")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClientBuilder.build());
Retrofit retrofit = builder.build();
// Get client and call object for the request
UserInfoClient client = retrofit.create(UserInfoClient.class);
String uniqueID = UUID.randomUUID().toString(); //UUID for the header
Call<UserInfoModel> call = client.createUser(uniqueID, userInfo);
call.enqueue(new Callback<UserInfoModel>() {
@Override
public void onResponse(Call<UserInfoModel> call, Response<UserInfoModel> response) {
Log.d(TAG, "1. onResponse: body: " + response.body() + "\n message: " + response.message()
+ "\n code: " + response.code() + "\n headers: " + response.headers() + " errorBody: " + response.errorBody()
+ "\n isSuccessful: " + response.isSuccessful() + "\n response: " + response);
if (response.isSuccessful()) {
Toast.makeText(ActivityUserInfo.this, "Upload Successful.", Toast.LENGTH_SHORT).show();
try {
JSONObject jsonObject = new JSONObject(new Gson().toJson(response.body()));
JSONArray userInfoObject = jsonObject.getJSONArray("userInfo");
JSONObject userIDObject = userInfoObject.getJSONObject(0);
Long userId = userIDObject.getLong("userId");
Log.d(TAG, "onResponse: 1.5: " + userId);
} catch (JSONException e) {
e.printStackTrace();
}
Log.d(TAG, "2. onResponse: 200: Upload Successful."
+ " statusCode: " + response.body().getStatusCode()
+ " statusMessage: " + response.body().getStatusMessage()
+ " user ID: " + response.body().getUserId()
+ "\n userInfo: " + response.body().getUserInfo().get(0));
}
else{
if(response.body() != null){
APIError apiError = ErrorUtils.parseError(response);
Toast.makeText(ActivityUserInfo.this, "3. Save not successful", Toast.LENGTH_SHORT).show();
Log.d(TAG, "3. onResponse: Save not successful"
+" ErrorUtils httpStatusCode: " + apiError.getHttpStatusCode()
+" ErrorUtils customCode: " + apiError.getCustomCode()
+" ErrorUtils message: " + apiError.getMessage());
}
else{
Log.d(TAG, "4. onResponse: response.body() is null");
}
}
}
@Override
public void onFailure(Call<UserInfoModel> call, Throwable t) {
Log.d(TAG, "4. onFailure: t: " + t + " message: " + t.getMessage() + " toString: " + t.toString()
+ " getCause: " + t.getCause() + " getStackTrace: " + t.getStackTrace());
Toast.makeText(ActivityUserInfo.this, "Please check you internet connection.", Toast.LENGTH_SHORT).show();
}
});
}
}
感谢您的帮助!
您需要将 UserInfoModel
模型 class 分成两部分:一个 class 代表“外部”对象(userInfo
、statusCode
, statusMessage
) 和一个 class 来表示数组中的项目。
public class UserInfoResponse {
private List<UserInfoItem> userInfo;
private int statusCode;
private String statusMessage;
// ...
}
public class UserInfoItem {
private String userFullName;
private String userPassword;
private String userName;
// ...
}
您现在将进行 Call<UserInfoResponse>
调用,并像这样访问列表中的项目:
UserInfoResponse response = // ...
String name = response.getUserInfo()[0].getUserName();
1st problem: How to get a value for the key "userId" from the API JSON response.
retrofit 可以自动将 JSON 对象转换为 POJO。所以你只需要让你的模型 classes.
对于 JSON 结果,您需要 2 个模型 classes.
根模型class
data class RootModel (
var userInfo: mutableList<UserInfoChild> = ArrayList(),
var statusCode: String = "",
var statusMessage: String = ""
)
UserInfoChild class
data class UserInfoChild (
var userId: Int = 0,
var userName: String? = "",
var userPassword: String? = ""
// add other fields
)
接下来,将 Call<UserInfoModel>
更改为 Call<RootModel>
最后,在 onResponse
方法中,您可以轻松访问 userId
字段。
val userId = response.body().userInfo[0].userId
2nd problem: status code is 500
在 URL 中使用两个反斜杠可能就是答案。如果你分享你的基地URL,那么解决它会更容易
我的问题有两个问题:问题 1 已由 hassan 和 Ben 解决。
至于问题 2 如何在 isSuccessful 为假的情况下解码响应,我不得不使用 response.errorBody() 而不是 response.body() 因为后者在我的 isSuccessful = false 情况下始终为 null .
以下代码对此 post 有所帮助:
Gson gson = new Gson();
try {
APIError errorResponse = gson.fromJson(response.errorBody().string(),APIError.class);
Log.d(TAG, "onResponse: message: " + errorResponse.getMessage()
+ " httpStatusCode: " + errorResponse.getHttpStatusCode()
+ " customCode: " + errorResponse.getCustomCode()
);
} catch (IOException e) {
e.printStackTrace();
}
其中 APIError.java 是 class for return 模型以防出错,类似于 hassan 和 Ben 建议的根模型:
public class APIError {
private int httpStatusCode;
private String customCode, message = "Unknown error.";
public APIError() {
}
public int getHttpStatusCode() {
return httpStatusCode;
}
public String getCustomCode() {
return customCode;
}
public String getMessage() {
return message;
}
}
我是第一次使用Retrofit。所以请不要介意愚蠢。 我有 2 个问题:
问题 1. 如何从 API JSON 响应中获取键“userId”的值。 (当 isSuccessful 为真时)以下是来自 API.
的响应我可以从下面乱七八糟的代码中得到userId,请教我一个更好的方法:
JSONObject jsonObject = new JSONObject(new Gson().toJson(response.body()));
JSONArray userInfoObject = jsonObject.getJSONArray("userInfo");
JSONObject userIDObject = userInfoObject.getJSONObject(0);
Long userId = userIDObject.getLong("userId");
问题二: onResponse 当 isSuccessful 为假时,response.body 显示为空。那么在这种情况下我如何访问 API JSON 响应。但是,在使用 Okhttp 日志记录时,我发现在这种情况下 okhttp 也会记录响应,但是 Retrofit 回调显示 response.body() 为空。
界面Class
public interface UserInfoClient {
@Headers("x-st-diagnostics-callerid: DKAPP-RETROFIT")
@POST("/api/User/")
Call<UserInfoModel> createUser(
@Header("x-st-diagnostics-correlationid") String uniqueID,
@Body UserInfoModel userInfo);
}
DataModel
public class UserInfoModel {
private List userInfo;
private String statusMessage;
private Integer statusCode;
private Long userId;
private String userFullName, userPassword, userName, userEmail, userMobileNumber, userWebsite, userDateOfBirth, userProfileText, userProfileDisplayPhoto, userProfileCoverPhoto;
public UserInfoModel(Long userId, String userFullName, String userPassword, String userName, String userEmail, String userMobileNumber, String userWebsite, String userDateOfBirth, String userProfileText, String userProfileDisplayPhoto, String userProfileCoverPhoto) {
this.userId = userId;
this.userFullName = userFullName;
this.userPassword = userPassword;
this.userName = userName;
this.userEmail = userEmail;
this.userMobileNumber = userMobileNumber;
this.userWebsite = userWebsite;
this.userDateOfBirth = userDateOfBirth;
this.userProfileText = userProfileText;
this.userProfileDisplayPhoto = userProfileDisplayPhoto;
this.userProfileCoverPhoto = userProfileCoverPhoto;
}
public Long getUserId() {
return userId;
}
public List getUserInfo() {
return userInfo;
}
public Integer getStatusCode() {
return statusCode;
}
public String getStatusMessage() {
return statusMessage;
}
}
Activity.java
public class ActivityUserInfo extends AppCompatActivity {
private static final String TAG = "ActivityUserInfo";
private EditText etUserId, etFullName, etPassword, etUsername, etEmail, etMobileNumber, etWebsite, etDob, etProfileTxt, etDispPhoto, etCoverPhoto;
private Button btnUpload;
public static Retrofit retrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate: begins");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_info);
etUserId = findViewById(R.id.et_userID);
etFullName = findViewById(R.id.et_fullName);
etPassword = findViewById(R.id.et_password);
etUsername = findViewById(R.id.et_username);
etEmail = findViewById(R.id.et_email);
etMobileNumber = findViewById(R.id.et_mobileNumber);
etWebsite = findViewById(R.id.et_website);
etDob = findViewById(R.id.et_dob);
etProfileTxt = findViewById(R.id.et_profileBio);
etDispPhoto = findViewById(R.id.et_profilePhoto);
etCoverPhoto = findViewById(R.id.et_coverPhoto);
btnUpload = findViewById(R.id.btn_uploadUserInfo);
btnUpload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
UserInfoModel userInfo = new UserInfoModel(
Long.parseLong(etUserId.getText().toString()),
etFullName.getText().toString(),
etPassword.getText().toString(),
etUsername.getText().toString(),
etEmail.getText().toString(),
etMobileNumber.getText().toString(),
etWebsite.getText().toString(),
etDob.getText().toString(),
etProfileTxt.getText().toString(),
etDispPhoto.getText().toString(),
etCoverPhoto.getText().toString()
);
sendNetworkRequest(userInfo);
}
});
}
private void sendNetworkRequest(UserInfoModel userInfo){
Log.d(TAG, "sendNetworkRequest: begins");
//Create okhttp client
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
//Adding logging interceptor tot he okHttp client
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
//set logging interceptor properties
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
//To redact a header from logging
logging.redactHeader("Content-Type");
//Disable logging interceptor in mode other than DEBUG.
if (BuildConfig.DEBUG) {
//Adding logging interceptor to the okHttpClient using okHttp client builder (conditional for debug only)
okHttpClientBuilder.addInterceptor(logging);
}
//Create Retrofit Instance
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://abc.ett.io")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClientBuilder.build());
Retrofit retrofit = builder.build();
// Get client and call object for the request
UserInfoClient client = retrofit.create(UserInfoClient.class);
String uniqueID = UUID.randomUUID().toString(); //UUID for the header
Call<UserInfoModel> call = client.createUser(uniqueID, userInfo);
call.enqueue(new Callback<UserInfoModel>() {
@Override
public void onResponse(Call<UserInfoModel> call, Response<UserInfoModel> response) {
Log.d(TAG, "1. onResponse: body: " + response.body() + "\n message: " + response.message()
+ "\n code: " + response.code() + "\n headers: " + response.headers() + " errorBody: " + response.errorBody()
+ "\n isSuccessful: " + response.isSuccessful() + "\n response: " + response);
if (response.isSuccessful()) {
Toast.makeText(ActivityUserInfo.this, "Upload Successful.", Toast.LENGTH_SHORT).show();
try {
JSONObject jsonObject = new JSONObject(new Gson().toJson(response.body()));
JSONArray userInfoObject = jsonObject.getJSONArray("userInfo");
JSONObject userIDObject = userInfoObject.getJSONObject(0);
Long userId = userIDObject.getLong("userId");
Log.d(TAG, "onResponse: 1.5: " + userId);
} catch (JSONException e) {
e.printStackTrace();
}
Log.d(TAG, "2. onResponse: 200: Upload Successful."
+ " statusCode: " + response.body().getStatusCode()
+ " statusMessage: " + response.body().getStatusMessage()
+ " user ID: " + response.body().getUserId()
+ "\n userInfo: " + response.body().getUserInfo().get(0));
}
else{
if(response.body() != null){
APIError apiError = ErrorUtils.parseError(response);
Toast.makeText(ActivityUserInfo.this, "3. Save not successful", Toast.LENGTH_SHORT).show();
Log.d(TAG, "3. onResponse: Save not successful"
+" ErrorUtils httpStatusCode: " + apiError.getHttpStatusCode()
+" ErrorUtils customCode: " + apiError.getCustomCode()
+" ErrorUtils message: " + apiError.getMessage());
}
else{
Log.d(TAG, "4. onResponse: response.body() is null");
}
}
}
@Override
public void onFailure(Call<UserInfoModel> call, Throwable t) {
Log.d(TAG, "4. onFailure: t: " + t + " message: " + t.getMessage() + " toString: " + t.toString()
+ " getCause: " + t.getCause() + " getStackTrace: " + t.getStackTrace());
Toast.makeText(ActivityUserInfo.this, "Please check you internet connection.", Toast.LENGTH_SHORT).show();
}
});
}
}
感谢您的帮助!
您需要将 UserInfoModel
模型 class 分成两部分:一个 class 代表“外部”对象(userInfo
、statusCode
, statusMessage
) 和一个 class 来表示数组中的项目。
public class UserInfoResponse {
private List<UserInfoItem> userInfo;
private int statusCode;
private String statusMessage;
// ...
}
public class UserInfoItem {
private String userFullName;
private String userPassword;
private String userName;
// ...
}
您现在将进行 Call<UserInfoResponse>
调用,并像这样访问列表中的项目:
UserInfoResponse response = // ...
String name = response.getUserInfo()[0].getUserName();
1st problem: How to get a value for the key "userId" from the API JSON response.
retrofit 可以自动将 JSON 对象转换为 POJO。所以你只需要让你的模型 classes.
对于 JSON 结果,您需要 2 个模型 classes.
根模型class
data class RootModel (
var userInfo: mutableList<UserInfoChild> = ArrayList(),
var statusCode: String = "",
var statusMessage: String = ""
)
UserInfoChild class
data class UserInfoChild (
var userId: Int = 0,
var userName: String? = "",
var userPassword: String? = ""
// add other fields
)
接下来,将 Call<UserInfoModel>
更改为 Call<RootModel>
最后,在 onResponse
方法中,您可以轻松访问 userId
字段。
val userId = response.body().userInfo[0].userId
2nd problem: status code is 500
在 URL 中使用两个反斜杠可能就是答案。如果你分享你的基地URL,那么解决它会更容易
我的问题有两个问题:问题 1 已由 hassan 和 Ben 解决。
至于问题 2 如何在 isSuccessful 为假的情况下解码响应,我不得不使用 response.errorBody() 而不是 response.body() 因为后者在我的 isSuccessful = false 情况下始终为 null .
以下代码对此 post 有所帮助:
Gson gson = new Gson();
try {
APIError errorResponse = gson.fromJson(response.errorBody().string(),APIError.class);
Log.d(TAG, "onResponse: message: " + errorResponse.getMessage()
+ " httpStatusCode: " + errorResponse.getHttpStatusCode()
+ " customCode: " + errorResponse.getCustomCode()
);
} catch (IOException e) {
e.printStackTrace();
}
其中 APIError.java 是 class for return 模型以防出错,类似于 hassan 和 Ben 建议的根模型:
public class APIError {
private int httpStatusCode;
private String customCode, message = "Unknown error.";
public APIError() {
}
public int getHttpStatusCode() {
return httpStatusCode;
}
public String getCustomCode() {
return customCode;
}
public String getMessage() {
return message;
}
}