You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新手求助:从API加载内容到TextView触发异常报错,求原因

问题分析与解决方案

嘿,作为Android新手遇到这个问题太正常啦,我来帮你拆解一下问题出在哪,以及怎么修复:

核心错误原因

  • 直接调用doInBackground()是大忌:AsyncTask的设计逻辑是通过execute()方法启动,它会自动将doInBackground()的逻辑放到子线程执行。你现在直接在onCreate()里调用doInBackground(),相当于在UI主线程里执行网络请求——Android从API 11开始就严格禁止主线程做网络操作,会直接抛出NetworkOnMainThreadException,这就是你触发异常的根本原因。
  • UI更新时机错误:就算你侥幸拿到了网络结果,直接在onCreate()里给TextView赋值也不安全。因为网络请求是异步操作,你同步获取返回值会阻塞主线程,导致界面卡顿;而且正确的做法是在AsyncTask的onPostExecute()方法里更新UI,这个方法是Android自动在主线程调用的,是安全的UI操作通道。
  • 参数传递不匹配:你的Down类继承AsyncTask<String, Void, String>,第一个泛型参数是String(代表传入的请求参数类型),但你调用时没传任何参数,虽然这不是触发异常的直接原因,但不符合AsyncTask的设计规范。

修正后的完整代码

public class MainActivity extends AppCompatActivity {
    private TextView textView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView1 = (TextView) findViewById(R.id.textView1);
        
        // 正确启动AsyncTask,无需传入参数(如果需要传URL可修改泛型后传入)
        new Down().execute();
    }

    private class Down extends AsyncTask<Void, Void, String> {
        @Override
        protected String doInBackground(Void... voids) {
            String result = "No";
            // 注意:替换成你自己的api_key
            String disc = "https://api.themoviedb.org/3/discover/movie?api_key=你的API_KEY&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1";
            try {
                URL url = new URL(disc);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                try {
                    BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    StringBuilder stb = new StringBuilder();
                    String line;
                    while ((line = br.readLine()) != null) {
                        stb.append(line).append("\n");
                    }
                    br.close();
                    result = stb.toString();
                } finally {
                    urlConnection.disconnect();
                }
            } catch (Exception e) {
                Log.e("ERROR", e.getMessage(), e);
                result = "There was an error";
            }
            Log.i("INFO", result);
            return result;
        }

        // 重写onPostExecute,在主线程安全更新UI
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            textView1.setText(result);
        }
    }
}

关键修改点说明

  1. 调整AsyncTask泛型为AsyncTask<Void, Void, String>,因为我们不需要传入请求参数(如果需要传递URL,可改回String并在execute()中传入对应字符串)。
  2. 用new Down().execute()替代直接调用doInBackground(),让AsyncTask自动完成线程调度。
  3. 添加onPostExecute()方法,将TextView的更新逻辑放在这里,确保UI操作在主线程执行。
  4. 将TextView引用提升为成员变量,方便在onPostExecute()中访问。

内容的提问来源于stack exchange,提问作者Divyansh Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:48:53