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

Android自定义View如何包含TextView?ListItem加载报错求助

解决自定义ListItem的Inflate错误与TextView空指针问题

你的核心问题是subjectNameTextView从未被初始化,始终为null,导致调用setText()或addView()时触发空指针异常。不管继承View还是RelativeLayout,都需要先正确初始化这个TextView。

方案一:使用XML布局定义ListItem结构(推荐)

这种方式将布局与逻辑分离,更易维护。

步骤1:创建ListItem的布局文件

新建res/layout/list_item_layout.xml,定义ListItem的UI结构:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/subject_name_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:padding="16dp"/>

</RelativeLayout>

步骤2:修改ListItem类

继承RelativeLayout,在构造方法中加载布局并初始化TextView,同时处理自定义属性(比如你XML里的app:title):

public class ListItem extends RelativeLayout {
    private String subjectName;
    private int backgroundColor;
    private TextView subjectNameTextView;

    // 必须实现三个构造方法,适配XML inflate场景
    public ListItem(Context context) {
        super(context);
        init(context, null);
    }

    public ListItem(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public ListItem(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        // 加载布局到当前ViewGroup
        LayoutInflater.from(context).inflate(R.layout.list_item_layout, this, true);
        // 初始化TextView
        subjectNameTextView = findViewById(R.id.subject_name_tv);

        // 读取XML中的自定义属性
        if (attrs != null) {
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ListItem);
            subjectName = ta.getString(R.styleable.ListItem_title);
            if (subjectName != null) {
                subjectNameTextView.setText(subjectName);
            }
            ta.recycle();
        }
    }

    public void setSubjectName(String subjectName) {
        this.subjectName = subjectName;
        if (subjectNameTextView != null) {
            subjectNameTextView.setText(subjectName);
        }
    }

    public void setColor(int backgroundColor) {
        this.backgroundColor = backgroundColor;
        setBackgroundColor(backgroundColor);
    }
}

步骤3:定义自定义属性

新建res/values/attrs.xml,添加自定义属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ListItem">
        <attr name="title" format="string"/>
    </declare-styleable>
</resources>

方案二:纯代码创建TextView

如果不想用XML布局,直接在代码中创建TextView并添加到ViewGroup:

public class ListItem extends RelativeLayout {
    private String subjectName;
    private int backgroundColor;
    private TextView subjectNameTextView;

    public ListItem(Context context) {
        super(context);
        init(context, null);
    }

    public ListItem(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public ListItem(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        // 创建TextView并设置布局参数
        subjectNameTextView = new TextView(context);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        params.setMargins(16, 16, 16, 16);
        subjectNameTextView.setLayoutParams(params);
        subjectNameTextView.setTextSize(16);
        // 添加到当前ViewGroup
        addView(subjectNameTextView);

        // 读取XML中的title属性
        if (attrs != null) {
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ListItem);
            subjectName = ta.getString(R.styleable.ListItem_title);
            if (subjectName != null) {
                subjectNameTextView.setText(subjectName);
            }
            ta.recycle();
        }
    }

    public void setSubjectName(String subjectName) {
        this.subjectName = subjectName;
        if (subjectNameTextView != null) {
            subjectNameTextView.setText(subjectName);
        }
    }

    public void setColor(int backgroundColor) {
        this.backgroundColor = backgroundColor;
        setBackgroundColor(backgroundColor);
    }
}

关键注意点

  • 自定义View必须实现三个构造方法,因为XML inflate时会调用带AttributeSet的构造方法。
  • 必须在init方法中完成TextView的初始化(不管是通过findViewById还是new),确保调用setText()或addView()时对象不为null。
  • 自定义属性需要在attrs.xml中声明,才能在XML布局中使用app:title这类属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 15:55:03