我收到了解析错误。请帮忙!如果有人知道Google Books API会很棒。如果你能解释我的错误在哪里;这会非常有帮助。谢谢。
E/QueryUtils: Problem parsing the library JSON results
org.json.JSONException: No value for items
at org.json.JSONObject.get(JSONObject.java:389)
at org.json.JSONObject.getJSONObject(JSONObject.java:609)
at com.example.android.booklisting.QueryUtils.extractFeatureFromJson(QueryUtils.java:172)
at com.example.android.booklisting.QueryUtils.fetchLibraryData(QueryUtils.java:57)
at com.example.android.booklisting.LibraryLoader.loadInBackground(LibraryLoader.java:50)
at com.example.android.booklisting.LibraryLoader.loadInBackground(LibraryLoader.java:16)
at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:57)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
SearchActivity类
package com.example.android.booklisting;
import android.app.LoaderManager;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class SearchActivity extends AppCompatActivity
implements LoaderManager.LoaderCallbacks<List<Library>> {
Button search;
EditText find;
private static final String LOG_TAG = SearchActivity.class.getName();
/**
* URL for Library data from the Google Books dataset
*/
private static String BOOKS_REQUEST_URL =
"https://www.googleapis.com/books/v1/volumes?q=";
/**
* Constant value for the earthquake loader ID. We can choose any integer.
* This really only comes into play if you're using multiple loaders.
*/
private static final int LIBRARY_LOADER_ID = 1;
private LibraryAdapter mAdapter;
private TextView mEmptyStateTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
search = (Button) findViewById(R.id.search_button);
search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
BOOKS_REQUEST_URL =BOOKS_REQUEST_URL+ find.getText().toString();
getLoaderManager().restartLoader();
}
});
find = (EditText) findViewById(R.id.search_text);}
});
// Find a reference to the {@link ListView} in the layout
ListView libraryListView = (ListView) findViewById(R.id.list);
mEmptyStateTextView = (TextView) findViewById(R.id.empty_view);
libraryListView.setEmptyView(mEmptyStateTextView);
// Create a new adapter that takes an empty list of earthquakes as input
mAdapter = new LibraryAdapter(this, new ArrayList<Library>());
// Set the adapter on the {@link ListView}
// so the list can be populated in the user interface
libraryListView.setAdapter(mAdapter);
// Set an item click listener on the ListView, which sends an intent to a web browser
// to open a website with more information about the selected library.
libraryListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// Find the current book that was clicked on
Library currentLibrary = mAdapter.getItem(position);
// Convert the String URL into a URI object (to pass into the Intent constructor)
Uri libraryUri = Uri.parse(currentLibrary.getUrl());
// Create a new intent to view the book URI
Intent websiteIntent = new Intent(Intent.ACTION_VIEW, libraryUri);
// Send the intent to launch a new activity
startActivity(websiteIntent);
}
});
// Get a reference to the ConnectivityManager to check state of network connectivity
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
// Get details on the currently active default data network
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
// If there is a network connection, fetch data
if (networkInfo != null && networkInfo.isConnected()) {
// Get a reference to the LoaderManager, in order to interact with loaders.
LoaderManager loaderManager = getLoaderManager();
// Initialize the loader. Pass in the int ID constant defined above and pass in null for
// the bundle. Pass in this activity for the LoaderCallbacks parameter (which is valid
// because this activity implements the LoaderCallbacks interface).
loaderManager.initLoader(LIBRARY_LOADER_ID, null, this);
} else {
// Otherwise, display error
// First, hide loading indicator so error message will be visible
View loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
// Update empty state with no connection error message
mEmptyStateTextView.setText(R.string.no_internet_connection);
}
}
@Override
public Loader<List<Library>> onCreateLoader(int i, Bundle bundle) {
// Create a new loader for the given URL
return new LibraryLoader(this, BOOKS_REQUEST_URL);
}
@Override
public void onLoadFinished(Loader<List<Library>> loader, List<Library> libraries) {
// Hide loading indicator because the data has been loaded
View loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
// Set empty state text to display "No books found."
mEmptyStateTextView.setText(R.string.no_libraries);
// Clear the adapter of previous library data
mAdapter.clear();
// If there is a valid list of {@link Library}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (libraries != null && !libraries.isEmpty()) {
mAdapter.addAll(libraries);
}
}
@Override
public void onLoaderReset(Loader<List<Library>> loader) {
// Loader reset, so we can clear out our existing data.
mAdapter.clear();
}
}
QueryUtils类:
import android.text.TextUtils;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* Helper methods related to requesting and receiving library data from Google Books.
*/
public class QueryUtils {
/** Tag for the log messages */
private static final String LOG_TAG = QueryUtils.class.getSimpleName();
/**
* Create a private constructor because no one should ever create a {@link QueryUtils} object.
* This class is only meant to hold static variables and methods, which can be accessed
* directly from the class name QueryUtils (and an object instance of QueryUtils is not needed).
*/
private QueryUtils() {
}
/**
* Query the USGS dataset and return a list of {@link Library} objects.
*/
public static List<Library> fetchLibraryData(String requestUrl) {
// Create URL object
URL url = createUrl(requestUrl);
// Perform HTTP request to the URL and receive a JSON response back
String jsonResponse = null;
try {
jsonResponse = makeHttpRequest(url);
} catch (IOException e) {
Log.e(LOG_TAG, "Problem making the HTTP request.", e);
}
// Extract relevant fields from the JSON response and create a list of {@link Library}s
List<Library> libraries = extractFeatureFromJson(jsonResponse);
// Return the list of {@link Earthquake}s
return libraries;
}
/**
* Returns new URL object from the given string URL.
*/
private static URL createUrl(String stringUrl) {
URL url = null;
try {
url = new URL(stringUrl);
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "Problem building the URL ", e);
}
return url;
}
/**
* Make an HTTP request to the given URL and return a String as the response.
*/
private static String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (url == null) {
return jsonResponse;
}
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem retrieving the earthquake JSON results.", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
// Closing the input stream could throw an IOException, which is why
// the makeHttpRequest(URL url) method signature specifies than an IOException
// could be thrown.
inputStream.close();
}
}
return jsonResponse;
}
/**
* Convert the {@link InputStream} into a String which contains the
* whole JSON response from the server.
*/
private static String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
return output.toString();
}
/**
* Return a list of {@link Library} objects that has been built up from
* parsing the given JSON response.
*/
private static List<Library> extractFeatureFromJson(String libraryJSON) {
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(libraryJSON)) {
return null;
}
// Create an empty ArrayList that we can start adding earthquakes to
List<Library> libraries = new ArrayList<>();
// Try to parse the JSON response string. If there's a problem with the way the JSON
// is formatted, a JSONException exception object will be thrown.
// Catch the exception so the app doesn't crash, and print the error message to the logs.
try {
// Create a JSONObject from the JSON response string
JSONObject baseJsonResponse = new JSONObject(libraryJSON);
// Extract the JSONArray associated with the key called "features",
// which represents a list of features (or libraries).
JSONArray libraryArray = baseJsonResponse.getJSONArray("items");
// For each book in the earthquakeArray, create an {@link Library} object
for (int i = 0; i < libraryArray.length(); i++) {
// Get a single book at position i within the list of books
JSONObject currentLibrary = libraryArray.getJSONObject(i);
// For a given book, extract the JSONObject associated with the
// key called "properties", which represents a list of all properties
// for that book.
JSONObject query = currentLibrary.getJSONObject("q");
// Extract the value for the key called "intitle"
String title = query.getString("intitle");
// Extract the value for the key called "inauthor"
String author = query.getString("inauthor");
String url = query.getString("info_url");
// Create a new {@link Library} object with the title, author,
// and url from the JSON response.
Library library = new Library(title, author, url);
// Add the new {@link Library} to the list of libraries.
libraries.add(library);
}
} catch (JSONException e) {
// If an error is thrown when executing any of the above statements in the "try" block,
// catch the exception here, so the app doesn't crash. Print a log message
// with the message from the exception.
Log.e("QueryUtils", "Problem parsing the library JSON results", e);
}
// Return the list of books
return libraries;
}
答案 0 :(得分:0)
我是否还需要在EditText上设置OnClickListener?
不,只需在点击按钮时从EditText
获取输入数据,然后在发出新请求之前将其添加到Google Books API
:
1。从EditText获取输入文本并将其添加到BOOKS_REQUEST_URL
:
BOOKS_REQUEST_URL=BOOKS_REQUEST_URL+ find.getText().toString();
注意:从BOOKS_REQUEST_URL
删除最终版并将网址更改为:
BOOKS_REQUEST_URL =
"https://www.googleapis.com/books/v1/volumes?q=";
2。最后在onCreateLoader
方法中调用触发器onClick
:
@Override
public void onClick(View view) {
BOOKS_REQUEST_URL=BOOKS_REQUEST_URL+ find.getText().toString();
getLoaderManager().initLoader(0, null, SearchActivity.this);
}