【问题标题】:selecting second item in onOptionsItemSelected causes app to crash在 onOptionsItemSelected 中选择第二个项目会导致应用程序崩溃
【发布时间】:2018-04-27 18:37:25
【问题描述】:

我正在尝试对正在查询的 URL 进行非常简单的更新。我根据选择了菜单中的哪个项目来更改 onOptionsItemSelected 中的 URL。如果我选择第一个项目,该应用程序效果很好。如果我选择第二项应用程序崩溃。为什么?两个 URL 均已验证正确。我相信选择第二项(highestRated)会导致 NetworkOnMainThreadException。任何调试帮助将不胜感激。

public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.mostPopular) {
        FILM_REQUEST_URL = "http://api.themoviedb.org/3/movie/popular?api_key=[MyNetworkKey]";
    } else if (item.getItemId() == R.id.highestRated) {
        FILM_REQUEST_URL = "http://api.themoviedb.org/3/movie/top_rated?api_key=[MyNetworkKey]";
    }

    // Clear the adapter of previous film data
    mAdapter.clear();

    // Get the revised film list
    List<Film> films = QueryUtils.fetchFilmData(FILM_REQUEST_URL);

    // Populate the adapters data set
    if (films != null && !films.isEmpty()) {
        mAdapter.addAll(films);
    }

    return super.onOptionsItemSelected(item);
}

Logcat 错误: Logcat Error Trace

QueryUtils.java:

公共类 QueryUtils {

private QueryUtils() {
}

/** Tag for log messages */
private static final String LOG_TAG = QueryUtils.class.getSimpleName();

/**
 * Query TMDb and return a list of {@link Film} objects
 */
public static List<Film> fetchFilmData(String requestUrl) {
    // Create a URL object
    URL url = createUrl(requestUrl);

    //Call HTTP request to URL and get JSON response
    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 return the list of films
    return extractFeatureFromJson(jsonResponse);
}

/**
 * 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 HTTP request to the 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
    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() == 200) {
            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 movie 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 that contains 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 Film} objects that has been built up from
 * parsing the given JSON response
 */
private static List<Film> extractFeatureFromJson(String filmJSON) {

    // If the JSON string is empty or null, then return
    if (TextUtils.isEmpty(filmJSON)) {
        return null;
    }

    // Create an empty ArrayList that we can start adding films to
    List<Film> films = 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
    try {

        // Create a JSONObject from the JSON response string
        JSONObject baseJsonResponse = new JSONObject(filmJSON);

        // Extract the JSONArray associated with the key called "results",
        // which represents a list of films
        JSONArray filmArray = baseJsonResponse.getJSONArray("results");

        // For each movie in the movieArray, create an {@link Film} object
        for (int i = 0; i < filmArray.length(); i++) {

            // Get a single movie at position i within the list of movies
            JSONObject currentFilm = filmArray.getJSONObject(i);

            // Extract the value for individual keys from JSONObject results
            int voteCount = currentFilm.getInt("vote_count");
            long voteAverage = currentFilm.getLong("vote_average");
            String title = currentFilm.getString("title");
            long popularity = currentFilm.getLong("popularity");
            String posterUrl = "http://image.tmdb.org/t/p/w185" + currentFilm.getString("poster_path");
            String overview = currentFilm.getString("overview");
            String releaseDate = currentFilm.getString("release_date");

            // Create a new {@link Film} object with the vote count, vote average, title,
            // popularity, poster path, overview, and release date from the JSON response
            Film film = new Film(voteCount, voteAverage, title, popularity, posterUrl,
                    overview, releaseDate);

            // Add the new {@link Film} to the list of movies
            films.add(film);
        }

    } 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 TMDb JSON results", e);
    }

    // Return the list of films
    return films;
}

}

【问题讨论】:

  • 这与 onOptionsItemSelected 无关。崩溃可能是由您的 fetchFilmData() 方法引起的。请发布崩溃的堆栈跟踪(来自 Logcat)和来自 fetchFilmData() 的代码。
  • @Ridcully 我已更新原始问题以包含 logcat 错误消息和 QueryUtils 代码。我同意你的观点,onOptionsItemSelected 不是问题,但我真的很困惑为什么我可以多次点击第一个菜单项(mostPopular)并且应用程序运行良好但只要我点击第二个菜单项它崩溃了。如果我交换 URL 也没关系,我仍然会遇到同样的问题。

标签: java android android-recyclerview


【解决方案1】:

发件人:https://developer.android.com/reference/android/os/NetworkOnMainThreadException

NetworkOnMainThreadException:

当应用程序尝试在其主线程上执行网络操作时引发的异常。

为避免此异常,您需要在单独的线程上发出 HTTP 请求。一种可能的方法是使用AsyncTask

Here 是一篇关于如何使用 AsyncTask 发出 HTTP GET 请求的 stackoverflow 帖子。

【讨论】:

  • Shoot 我以为我在使用 AsyncTask 但显然不是。现在重新编写代码,但这应该可以修复它。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-28
相关资源
最近更新 更多