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

如何从JSON API获取URL在RecyclerView点击事件打开 空指针排查

实现目标

从JSON接口返回数据中提取URL链接,在RecyclerView的点击事件中打开对应链接。

现有代码

接口返回JSON结构

{
  {
    "link": "https://example.com"
  },
  {
    ...
  }
}

URLModel类

public class URLModel {
    String Link;
    public MonlixModel(String link) {
        Link = link;
    }

    public String getLink() {
        return Link;
    }

    public void setLink(String link) {
        Link = link;
    }
}

URLAdapter适配器

public class URLAdapter extends RecyclerView.Adapter<URLAdapter.URLHolder> {
    Context mContext;
    List<URLModel> urlModels;

    public URLAdapter(Context mContext, List<URLAdapter> urlModels) {
        this.mContext = mContext;
        this.urlModels= urlModels;
    }

    @NonNull
    @Override
    public URLHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view, parent, false);
        return new URLHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull URLHolder holder, int position) {
        holder.recyclerUrl.setOnClickListener(view -> {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(urlModels.get(position).getLink()));
            mContext.startActivity(intent);
        });
    }

    @Override
    public int getItemCount() {
        return urlModels.size();
    }

    public static class URLHolder extends RecyclerView.ViewHolder {
        private final RecyclerView recyclerUrl;

        public URLHolder(@NonNull View itemView) {
            super(itemView);
            recyclerUrl = itemView.findViewById(R.id.recycler_url);
        }
    }
}

网络请求逻辑(Volley实现)

private void getData() {
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        @SuppressLint("NotifyDataSetChanged") JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, Apis.JSON_API, null, response -> {
            for(int i = 0; i <=response.length(); i++){
                try {
                    JSONObject jsonObject = response.getJSONObject(i);
                    URLModelList.add(new URLModel(
                            jsonObject.getString("link")
                    ));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            URLAdapter adapter = new URLAdapter(getApplicationContext(), URLModelList);
            recyclerView.setAdapter(adapter);
            adapter.notifyDataSetChanged();
            Toast.makeText(Main.this, "Success", Toast.LENGTH_SHORT).show();
        }, error -> Toast.makeText(Main.this, error.getMessage(), Toast.LENGTH_SHORT).show());
        requestQueue.add(jsonArrayRequest);
    }

现存问题

运行时抛出空指针异常,初步怀疑问题在Adapter层。使用Volley作为网络框架,曾尝试将URLModel的String字段改为Uri类型,但JSONObject无对应getUri方法,无法实现。

错误点定位与修复

代码中共有6处会导致崩溃或功能异常的问题,逐一修复即可:

  1. URLModel构造方法名错误:类名为URLModel,构造方法写成了MonlixModel,创建对象时会找不到匹配构造方法。
  2. Adapter构造方法参数类型错误:第二个参数声明为List<URLAdapter>,实际需要传入List<URLModel>,类型不匹配会导致后续读取数据时空指针。
  3. ViewHolder中控件类型声明错误:R.id.recycler_url是item布局中的普通可点击控件,声明为RecyclerView类型会导致findViewById返回null,设置点击事件时直接触发空指针。
  4. JSON遍历数组越界:循环条件写为i <=response.length(),JSON数组下标从0开始,正确条件应为i < response.length(),否则最后一次循环会取到不存在的下标,触发JSONException导致数据添加失败。
  5. 请求类型与返回结构不匹配:当前使用JsonArrayRequest要求接口最外层返回JSON数组([]包裹),贴出的返回结构最外层为JSON对象({}包裹),会直接请求失败拿不到数据。如果接口实际返回最外层是对象,需要替换为JsonObjectRequest。
  6. Intent缺少必要Flag:使用Application上下文启动Activity时,必须添加Intent.FLAG_ACTIVITY_NEW_TASK标记,否则会抛出运行时异常。

修复后代码

修复后URLModel

public class URLModel {
    String link;
    // 构造方法名与类名保持一致
    public URLModel(String link) {
        this.link = link;
    }

    public String getLink() {
        return link;
    }

    public void setLink(String link) {
        this.link = link;
    }
}

修复后URLAdapter

public class URLAdapter extends RecyclerView.Adapter<URLAdapter.URLHolder> {
    Context mContext;
    List<URLModel> urlModels;

    // 修正参数类型为List<URLModel>
    public URLAdapter(Context mContext, List<URLModel> urlModels) {
        this.mContext = mContext;
        this.urlModels = urlModels;
    }

    @NonNull
    @Override
    public URLHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view, parent, false);
        return new URLHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull URLHolder holder, int position) {
        URLModel currentItem = urlModels.get(position);
        holder.itemView.setOnClickListener(view -> {
            String link = currentItem.getLink();
            // 链接为空时直接拦截,避免Uri.parse解析失败
            if (link == null || link.trim().isEmpty()) {
                Toast.makeText(mContext, "链接无效", Toast.LENGTH_SHORT).show();
                return;
            }
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(link));
            // 非Activity上下文启动Activity添加Flag
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(intent);
        });
    }

    @Override
    public int getItemCount() {
        // 增加空判断,避免列表未初始化时size调用空指针
        return urlModels == null ? 0 : urlModels.size();
    }

    public static class URLHolder extends RecyclerView.ViewHolder {
        // 若需要给指定id的控件加点击,替换为对应控件类型即可,比如TextView、Button
        private final View clickArea;

        public URLHolder(@NonNull View itemView) {
            super(itemView);
            clickArea = itemView.findViewById(R.id.recycler_url);
        }
    }
}

修复后网络请求逻辑

private void getData() {
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        // 注意:如果接口最外层返回的是JSONObject,把JsonArrayRequest换成JsonObjectRequest即可
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, Apis.JSON_API, null, response -> {
            // 每次加载前清空旧数据,避免重复添加
            URLModelList.clear();
            // 修正循环条件,避免数组越界
            for(int i = 0; i < response.length(); i++){
                try {
                    JSONObject jsonObject = response.getJSONObject(i);
                    // 用optString取字段,字段不存在时返回默认空字符串,不会抛异常
                    String link = jsonObject.optString("link", "");
                    if (!link.isEmpty()) {
                        URLModelList.add(new URLModel(link));
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            // 不要每次请求都新建Adapter,初始化绑定一次即可,后续只刷新数据
            if (recyclerView.getAdapter() == null) {
                // 优先传Activity上下文,避免Context相关异常
                URLAdapter adapter = new URLAdapter(Main.this, URLModelList);
                recyclerView.setAdapter(adapter);
            } else {
                recyclerView.getAdapter().notifyDataSetChanged();
            }
            Toast.makeText(Main.this, "加载成功", Toast.LENGTH_SHORT).show();
        }, error -> Toast.makeText(Main.this, "加载失败:" + error.getMessage(), Toast.LENGTH_SHORT).show());
        requestQueue.add(jsonArrayRequest);
    }

补充说明
  • Volley完全满足当前网络请求需求,不需要更换框架。URLModel中保留String类型存储链接即可,使用时调用Uri.parse()转成Uri对象,不需要修改字段类型。
  • 记得在AndroidManifest.xml中添加网络权限:<uses-permission android:name="android.permission.INTERNET" />。Android 11及以上版本需要在manifest中添加queries配置,否则可能无法正常唤起浏览器跳转。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:27:40