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

使用类系统开发Todo App遇空指针异常,求解决方法

问题排查与解决:Android Todo App空指针异常

错误核心原因

报错Attempt to invoke virtual method 'void android.widget.LinearLayout.addView(android.view.View)' on a null object reference,根源有两处:

  • 自定义View未加载布局文件:card类继承自LinearLayout,但未加载cardbg.xml布局,导致bg = findViewById(R.id.cardbg)返回null,调用bg.addView(clon)时触发空指针。
  • 错误获取父布局引用:card类中main = findViewById(R.id.main)无法获取Activity中的main布局,因为findViewById仅在当前View层级内查找,main属于Activity布局而非card的子布局,此引用同样为null,后续克隆、删除操作也会失效。

修复步骤及完整代码

1. 修改MainActivity.java,传递父布局引用

package com.thehuman.todo;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {
    LinearLayout main;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        main = findViewById(R.id.main);
        // 将main布局引用传递给Card
        Card first = new Card(MainActivity.this, main);
        main.addView(first);
    }
}

2. 重构Card类(遵循Java类名大写规范),加载布局并修正逻辑

package com.thehuman.todo;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import androidx.core.content.ContextCompat;

public class Card extends LinearLayout {
    private final LinearLayout parentMain;
    private LinearLayout bg;
    private Button cloneBtn, deleteBtn;

    public Card(Context context, LinearLayout mainLayout) {
        super(context);
        parentMain = mainLayout;
        // 加载cardbg.xml布局到当前Card中
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.cardbg, this, true);
        
        // 获取cardbg布局引用
        bg = findViewById(R.id.cardbg);
        
        initButtons(context);
        setButtonListeners();
    }

    private void initButtons(Context context) {
        cloneBtn = new Button(context);
        cloneBtn.setBackgroundColor(ContextCompat.getColor(context, R.color.white));
        cloneBtn.setPadding(20, 20, 20, 20);
        cloneBtn.setTextColor(ContextCompat.getColor(context, R.color.teal_200));
        cloneBtn.setText("clone me");

        deleteBtn = new Button(context);
        deleteBtn.setBackgroundColor(ContextCompat.getColor(context, R.color.black));
        deleteBtn.setTextColor(ContextCompat.getColor(context, R.color.teal_200));
        deleteBtn.setPadding(20, 20, 20, 20);
        deleteBtn.setText("delete me");

        // 将按钮添加到bg布局
        bg.addView(cloneBtn);
        bg.addView(deleteBtn);
    }

    private void setButtonListeners() {
        cloneBtn.setOnClickListener(v -> {
            Card clonedCard = new Card(getContext(), parentMain);
            parentMain.addView(clonedCard);
        });

        deleteBtn.setOnClickListener(v -> parentMain.removeView(Card.this));
    }
}

额外修正点

  • 用ContextCompat.getColor()替代直接使用R.color.xxx设置颜色,避免资源ID与颜色值混淆导致的显示异常。
  • 移除冗余的self引用,直接用Card.this指代当前实例。
  • 加载布局时将LayoutInflater.inflate第三个参数设为true,确保布局被添加到当前Card容器中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 00:24:16