如何从指定JSON URL获取数据并设置到多个TextView?
Hey there! Let's walk through how to properly fetch that JSON data and populate your TextViews correctly. I'll break this down step by step so it's easy to follow:
Before you do anything else, make sure your app has permission to access the internet. Open your AndroidManifest.xml and add this line outside the <application> tag:
<uses-permission android:name="android.permission.INTERNET" />
If your API uses HTTP (not HTTPS) and you're targeting Android 9+, you'll also need to add this attribute to your <application> tag to allow cleartext traffic:
android:usesCleartextTraffic="true"
Android blocks network operations on the main thread (it causes ANRs, or app not responding errors), so you need to run the request in the background. Below are two common approaches:
Option 1: Using AsyncTask (Java)
This is a basic, built-in way to handle background tasks:
public class FetchUserDataTask extends AsyncTask<Void, Void, JSONObject> { private final Context mContext; private final TextView mUsernameView; private final TextView mPointsView; // Pass in your TextViews so we can update them later public FetchUserDataTask(Context context, TextView usernameView, TextView pointsView) { mContext = context; mUsernameView = usernameView; mPointsView = pointsView; } @Override protected JSONObject doInBackground(Void... voids) { JSONObject responseJson = null; try { // Create the URL connection URL url = new URL("https://www.lurkinator.net/api/data?username=bobtheshoplifter_"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.connect(); // Read the response into a string BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); StringBuilder responseBuilder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { responseBuilder.append(line); } reader.close(); // Convert the string to a JSONObject responseJson = new JSONObject(responseBuilder.toString()); } catch (IOException | JSONException e) { e.printStackTrace(); // Log or handle errors here (e.g., network failure) } return responseJson; } @Override protected void onPostExecute(JSONObject jsonObject) { super.onPostExecute(jsonObject); if (jsonObject == null) { Toast.makeText(mContext, "Failed to fetch data", Toast.LENGTH_SHORT).show(); return; } try { // Extract the fields from JSON String username = jsonObject.getString("username"); int points = jsonObject.getInt("points"); // Update the TextViews (this runs on the main thread) mUsernameView.setText(username); mPointsView.setText(String.valueOf(points)); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(mContext, "Data format error", Toast.LENGTH_SHORT).show(); } } }
To use this task in your Activity:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout); TextView usernameTv = findViewById(R.id.username_textview); TextView pointsTv = findViewById(R.id.points_textview); // Start the background task new FetchUserDataTask(this, usernameTv, pointsTv).execute(); }
Option 2: Using Coroutines (Kotlin, Modern Approach)
If you're using Kotlin, Coroutines are the recommended way to handle background tasks cleanly:
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.json.JSONObject import java.net.URL class YourActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.your_layout) fetchAndDisplayUserData() } private fun fetchAndDisplayUserData() { val usernameTv = findViewById<TextView>(R.id.username_textview) val pointsTv = findViewById<TextView>(R.id.points_textview) CoroutineScope(Dispatchers.IO).launch { val jsonString = try { // Fetch the data in the IO thread URL("https://www.lurkinator.net/api/data?username=bobtheshoplifter_").readText() } catch (e: Exception) { withContext(Dispatchers.Main) { Toast.makeText(this@YourActivity, "Network error", Toast.LENGTH_SHORT).show() } return@launch } val userData = try { // Parse the JSON JSONObject(jsonString) } catch (e: Exception) { withContext(Dispatchers.Main) { Toast.makeText(this@YourActivity, "Data parse error", Toast.LENGTH_SHORT).show() } return@launch } // Extract values val username = userData.getString("username") val points = userData.getInt("points") // Update UI on main thread withContext(Dispatchers.Main) { usernameTv.text = username pointsTv.text = points.toString() } } } }
- Never run network code on the main thread: This will cause your app to freeze and possibly crash.
- Handle exceptions: Always catch network errors, JSON parsing errors, and missing fields (in case the API response changes).
- Consider using libraries: For larger apps, libraries like Retrofit + Gson can simplify network requests and automatic JSON parsing into data classes, which reduces boilerplate code.
内容的提问来源于stack exchange,提问作者Daniel Christensen

