安卓应用调用维基百科API获取随机文章时崩溃:java.lang.reflect.InvocationTargetException及JSONException问题排查
Let's walk through the issues causing your app to crash and fix them one by one:
1. Mismatched API URL (The Root Cause)
First off, the URL in your fetchdata() function is not the random article API you intended to use. Right now, you're hitting an endpoint that fetches categories starting with "List of" instead of random articles. That’s why your JSON parsing is failing—you’re expecting an allcategories array that doesn’t exist in the random article response.
Replace your current URL with the one you mentioned (note: use & instead of & in code, since & is HTML-encoded and unnecessary here):
val url = "https://en.wikipedia.org/w/api.php?format=json&action=query&generator=random&grnnamespace=0&prop=revisions|images&rvprop=content&grnlimit=10"
2. Fix JSON Parsing Logic
The random article API returns a completely different structure than the category endpoint. The article data lives under query -> pages (a JSON object, not an array). Here's how to parse it correctly, with safeguards against missing values to avoid JSONException:
private fun fetchdata() { // Correct random article API URL val url = "https://en.wikipedia.org/w/api.php?format=json&action=query&generator=random&grnnamespace=0&prop=revisions|images&rvprop=content&grnlimit=10" val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null, Response.Listener{ response -> val itemarray = ArrayList<images>() // Adjust based on your data class // Extract the query object first val queryObj = response.getJSONObject("query") // Get the pages object (keys are page IDs, values hold article details) val pagesObj = queryObj.getJSONObject("pages") // Iterate through each article in the pages object val pageKeys = pagesObj.keys() while (pageKeys.hasNext()) { val pageId = pageKeys.next() val pageObj = pagesObj.getJSONObject(pageId) // Safely extract values (use opt methods to avoid NoValue exceptions) val articleTitle = pageObj.optString("title", "Untitled Article") // Note: rvprop=content pulls full article text (huge!)—use rvprop=summary for shorter snippets instead val articleContent = pageObj.optJSONArray("revisions") ?.optJSONObject(0) ?.optString("*", "No content available") ?: "No content available" // Add to your list (match your images class constructor) itemarray.add(images(articleTitle, articleContent)) } madapter.update_img(itemarray) }, { error -> Log.d("wkiki","Something went wrong: ${error.message}") // Optional: Show a user-friendly error toast here }) MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest) }
3. Extra Tips to Prevent Future Crashes
- Network Permission: Double-check you have
<uses-permission android:name="android.permission.INTERNET" />in yourAndroidManifest.xml—missing this can cause silent failures or crashes. - Empty Data Handling: Add a check if
itemarrayis empty after parsing, and update your UI to show a "No articles found" message instead of crashing. - Optimize API Request: Using
rvprop=contentpulls the full article text, which is overkill for most apps. Swap it forrvprop=summaryin the URL to get concise snippets and improve performance. - Null Safety First: Always use
optString(),optJSONObject(), etc., instead ofgetString()orgetJSONObject()—these methods return default values when keys are missing, avoidingJSONException.
内容的提问来源于stack exchange,提问作者hhmm_11

