我创建了一个使用Google Books API的Android应用程序。当我从服务器获得JSON响应时,我解析响应并检索标题,作者,类别,发布者,页数,缩略图以及有关该书的更多信息。问题是JSON响应中的某些书籍没有缩略图键或类别键。当我尝试获取这些JSON键值时,程序会抛出错误,因此在发生错误后会跳过添加其他书籍的代码。
我用嵌套尝试了catch块解决了这个问题。例如,如果响应中没有发布者密钥,那么我将返回null。
String publisher;
try {
publisher = volumeInfo.getString("publisher");
} catch (JSONException e) {
publisher = null;
}
以下是解析JSON响应的整个方法如下所示:
private List<BookData> parseJsonResponse(String jsonResponse) {
List<BookData> bookData = new ArrayList<>();
try {
JSONObject rootObject = new JSONObject(jsonResponse);
JSONArray itemsArray = rootObject.getJSONArray("items");
for (int i = 0; i < itemsArray.length(); i++) {
JSONObject itemObject = itemsArray.getJSONObject(i);
JSONObject volumeInfo =
itemObject.getJSONObject("volumeInfo");
String title;
try {
title = volumeInfo.getString("title");
} catch (JSONException e) {
title = null;
}
ArrayList<String> authors;
try {
JSONArray authorsArray =
volumeInfo.getJSONArray("authors");
authors = new ArrayList<>();
for (int j = 0; j < authorsArray.length(); j++) {
authors.add(authorsArray.getString(j));
}
} catch (JSONException e) {
authors = null;
}
ArrayList<String> categories;
try {
JSONArray categoriesArray =
volumeInfo.getJSONArray("categories");
categories = new ArrayList<>();
for (int k = 0; k < categoriesArray.length(); k++) {
categories.add(categoriesArray.getString(k));
}
} catch (JSONException e) {
categories = null;
}
String publisher;
try {
publisher = volumeInfo.getString("publisher");
} catch (JSONException e) {
publisher = null;
}
String publishedDate;
try {
publishedDate =
volumeInfo.getString("publishedDate");
} catch (JSONException e) {
publishedDate = null;
}
int pageCount;
try {
pageCount = volumeInfo.getInt("pageCount");
} catch (JSONException e) {
pageCount = 0;
}
String language;
try {
language = volumeInfo.getString("language");
} catch (JSONException e) {
language = null;
}
String description;
try {
description = volumeInfo.getString("description");
} catch (JSONException e) {
description = null;
}
String bookWebsite;
try {
bookWebsite = volumeInfo.getString("infoLink");
} catch (JSONException e) {
bookWebsite = null;
}
Bitmap thumbnail;
try {
JSONObject imageLink =
volumeInfo.getJSONObject("imageLinks");
String thumbnailUrl =
imageLink.getString("thumbnail");
thumbnail = getThumbnailBitmap(thumbnailUrl);
} catch (JSONException e) {
thumbnail = null;
}
// Add a new BookData object to the list
bookData.add(new BookData(title, thumbnail, authors,
categories, publisher, publishedDate,
pageCount, language, description,
bookWebsite));
}
} catch (JSONException e) {
Log.e(LOG_TAG, null, e);
}
return bookData;
}
完成解析后,我必须更新我的观点。我正在使用列表视图,因此适配器需要处理视图通胀。 我必须添加一个if语句来检查变量是否为null,然后例如设置文本视图的文本。另外,我将文本设置为&#34;发布者不可用&#34;。
TextView publisher = listView.findViewById(R.id.book_publisher);
if (bookData.getPublisher() != null) {
publisher.setText(bookData.getPublisher());
} else {
publisher.setText("Publisher not available");
}
以下是整个适配器的外观:
public class BookDataAdapter extends ArrayAdapter<BookData> {
public BookDataAdapter(@NonNull Context context, @NonNull
List<BookData> bookDatas) {
super(context, 0, bookDatas);
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView,
@NonNull ViewGroup parent) {
View listView = convertView;
if (listView == null) {
listView = LayoutInflater.from(getContext())
.inflate(R.layout.book_list_item, parent, false);
}
// Get current BookData object
BookData bookData = getItem(position);
ImageView thumbnail = listView.findViewById(R.id.book_thumbnail);
if (bookData.getThumbnail() != null) {
thumbnail.setImageBitmap(bookData.getThumbnail());
} else {
// Set default thumbnail
thumbnail.setImageResource(R.drawable.default_thumbnail);
}
TextView title = listView.findViewById(R.id.book_title);
if (bookData.getTitle() != null) {
title.setText(bookData.getTitle());
} else {
title.setText("Title not available");
}
TextView author = listView.findViewById(R.id.book_author);
if (bookData.getAuthors() != null) {
author.setText(listToString(bookData.getAuthors()));
} else {
author.setText("Authors not available");
}
TextView category = listView.findViewById(R.id.book_category);
if (bookData.getCategories() != null) {
category.setText("Category: " +
listToString(bookData.getCategories()));
} else {
category.setText("Category not available ");
}
TextView publisher = listView.findViewById(R.id.book_publisher);
if (bookData.getPublisher() != null) {
publisher.setText(bookData.getPublisher() + ", ");
} else {
publisher.setText("Publisher not available, ");
}
TextView publishedDate =
listView.findViewById(R.id.book_published_date);
if (bookData.getPublishedDate() != null) {
publishedDate.setText(bookData.getPublishedDate());
} else {
publishedDate.setText("Published date not available");
}
TextView pageCount = listView.findViewById(R.id.book_page_count);
if (bookData.getPageCount() != 0) {
pageCount.setText("Pages: " + bookData.getPageCount());
} else {
pageCount.setText("Page count not available");
}
TextView language = listView.findViewById(R.id.book_language);
if (bookData.getLanguage() != null) {
language.setText(bookData.getLanguage());
} else {
language.setText("Language not available");
}
TextView description =
listView.findViewById(R.id.book_description);
if (bookData.getDescription() != null) {
description.setText(bookData.getDescription());
} else {
description.setText("Description not available");
}
return listView;
}
private String listToString(List<String> list) {
if (list == null || list.size() == 0) {
return null;
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
builder.append(list.get(i));
if (i == (list.size() - 1)) {
break;
}
builder.append(", ");
}
return builder.toString();
}
}
最后我想问一个问题。是否有更好的方法或更有效的方法使用不同的密钥解析JSON响应,因为有些人说嵌套的try catch语句不是一个好的做法?
非常感谢!!
答案 0 :(得分:1)
您有两种选择:
使用.has()
:
String publisher = null;
if(volumeInfo.has("publisher")){
publisher = volumeInfo.getString("publisher");
}
使用opt
代替get
(更好,IMO):
String publisher = volumeInfo.optString("publisher");
opt###
方法对于对象默认为null
,对于基元默认为0
/ false
,因此您不必编写try/catch
块或if
条件。您还可以将第二个参数指定为默认值:
String publisher = volumeInfo.optString("publisher", "no publisher");
// if publisher is not a valid key, "no publisher" will be returned
答案 1 :(得分:0)
使用.has()
JSONObject
属性
if(volumeInfo.has("publisher")){
volumeInfo.getString("publisher");
}
答案 2 :(得分:0)
您不需要在单独的try / catch块中包装json操作。
json库中有一个方法可以解决这个问题:
jsonObject.isNull(key);
当您尝试按键获取值时,请按以下方式写入:
if (!volumeInfo.isNull("categories")) {
JSONArray categoryArray = volumeInfo.getJSONArray("categories");
}