新手求助:从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); } } }
关键修改点说明
- 调整AsyncTask泛型为
AsyncTask<Void, Void, String>,因为我们不需要传入请求参数(如果需要传递URL,可改回String并在execute()中传入对应字符串)。 - 用
new Down().execute()替代直接调用doInBackground(),让AsyncTask自动完成线程调度。 - 添加
onPostExecute()方法,将TextView的更新逻辑放在这里,确保UI操作在主线程执行。 - 将TextView引用提升为成员变量,方便在
onPostExecute()中访问。
内容的提问来源于stack exchange,提问作者Divyansh Singh
相关产品推荐
相关产品推荐

