使用类系统开发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
相关产品推荐
相关产品推荐

