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

Android技术问题:AsyncTask获取HTTP数据失败,RecyclerView关联空指针报错

问题分析与解决方案

先看你最直接的崩溃:NullPointerException是因为你把AtomicReference<MyCustomAdapter> adapter初始化为null,然后直接调用adapter.set(...)——空对象当然不能调用方法啦!这是最容易解决的问题,但背后还有几个更关键的概念误解需要理清,不然就算修复这个崩溃,你的App还是会有问题(比如主线程阻塞、数据加载异常)。

一、先修复直接崩溃的问题

把AtomicReference<MyCustomAdapter> adapter = null;改成:

AtomicReference<MyCustomAdapter> adapter = new AtomicReference<>();

不过说实话,这里完全没必要用AtomicReference,直接用普通的MyCustomAdapter变量就行,因为你是在主线程同步操作的,原子类是给多线程并发场景用的。

二、解决核心问题:AsyncTask的错误用法

你用task.execute(...).get()直接阻塞了主线程!这完全违背了AsyncTask设计的初衷——异步任务就是要在后台线程干活,主线程继续响应用户操作,等后台任务完成后再更新UI。get()会强制主线程等待后台任务完成,不仅可能导致ANR(应用无响应),还会让你的界面卡住。

正确的做法是重写AsyncTask的onPostExecute方法,在这个方法里处理数据并更新RecyclerView。

三、完整修正后的代码

public class MainActivity extends AppCompatActivity { 
    private List<Message> list;
    private RecyclerView recyclerView;
    private MyCustomAdapter adapter;

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 

        // 初始化RecyclerView相关组件
        recyclerView = findViewById(R.id.recyclerView);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setHasFixedSize(true);

        // 初始化数据列表
        list = new ArrayList<>();
        // 先设置空适配器,避免界面空白
        adapter = new MyCustomAdapter(list);
        recyclerView.setAdapter(adapter);

        // 启动异步下载任务
        DownloadTask task = new DownloadTask();
        task.execute("https://newsapi.org/v2/top-headlines?country=us&apiKey=(MyApi)");
    } 

    private void representData(String myJSONDataString){
        if (myJSONDataString == null || myJSONDataString.equals("Failed")) {
            // 数据加载失败,做提示或者其他处理
            Log.e("MainActivity", "数据加载失败");
            return;
        }
        JsonParser parser = new JsonParser(); 
        JsonObject rootObj = parser.parse(myJSONDataString).getAsJsonObject(); 
        JsonArray articlesArray = rootObj.getAsJsonArray("articles"); 
        for (JsonElement aa : articlesArray) { 
            JsonObject articleObj = aa.getAsJsonObject(); 
            // 这里最好加非空判断,避免JSON字段缺失导致崩溃
            String title = articleObj.has("title") ? articleObj.get("title").getAsString() : "无标题";
            String description = articleObj.has("description") ? articleObj.get("description").getAsString() : "无描述";
            list.add(new Message(title,description)); 
        }
        // 数据更新后通知适配器刷新UI
        adapter.notifyDataSetChanged();
    } 

    public class DownloadTask extends AsyncTask<String, Void, String> { 
        @Override 
        protected String doInBackground(String... urls) { 
            String result = ""; 
            URL url; 
            HttpURLConnection urlConnection = null; 
            try { 
                url = new URL(urls[0]); 
                urlConnection = (HttpURLConnection)url.openConnection(); 
                InputStream in = urlConnection.getInputStream(); 
                InputStreamReader reader = new InputStreamReader(in); 
                // 用StringBuilder拼接字符串,比直接用result+=current效率高很多
                StringBuilder sb = new StringBuilder();
                int data = reader.read(); 
                while (data != -1) { 
                    char current = (char) data; 
                    sb.append(current); 
                    data = reader.read(); 
                } 
                return sb.toString(); 
            } catch(Exception e) { 
                e.printStackTrace(); 
                return "Failed"; 
            } finally {
                // 别忘了关闭连接,避免资源泄漏
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
            }
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            // 后台任务完成后,在主线程处理数据并更新UI
            representData(result);
            Log.i("result","Heh "+result);
        }
    } 
}

四、你需要理清的核心概念

  1. Android主线程不能阻塞:任何耗时操作(比如网络请求)都不能放在主线程,AsyncTask的doInBackground是后台线程,onPostExecute是主线程,要在这两个方法之间分工。
  2. RecyclerView的初始化时机:应该先把RecyclerView的布局管理器、适配器都设置好,哪怕是空数据的适配器,这样界面一开始就有正确的布局,等数据加载完成后再调用notifyDataSetChanged刷新。
  3. JSON数据的安全性处理:永远不要假设返回的JSON字段一定存在,要加has()判断,避免字段缺失导致崩溃。
  4. 资源泄漏问题:网络连接用完一定要关闭,不然会浪费系统资源。

另外,你提到尝试过OkHttp、Retrofit但问题没解决,其实核心不是网络库的问题,而是你对Android异步操作和UI更新的逻辑理解有偏差。Retrofit本身就是异步设计的,用它的话可以避免自己写AsyncTask的繁琐,建议你后续可以深入学习Retrofit的异步回调或者Coroutine(协程),这是现在Android开发更推荐的异步方式。

内容的提问来源于stack exchange,提问作者Grigory Shimichev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:24:17