向SQLite数据库插入数据时触发NullPointerException问题求助
解决SQLite插入数据时的NullPointerException问题
看起来你遇到的空指针问题根源很明确——在Fragment还未依附到Activity时就尝试获取Context来初始化SQLiteHelper,导致传入Db的Context为null,进而触发了getDatabasePath的空指针调用。
问题分析
你在StartFragment里直接把Db db = new Db(getActivity());作为成员变量初始化,但Fragment的生命周期里,成员变量初始化的时机远早于Fragment依附到Activity的时机(比如onAttach或onCreateView之前),这时候getActivity()返回的是null,传入Db的Context自然也是null。当你调用insertData时,this.getWritableDatabase()内部需要用到Context,就会抛出空指针异常。
另外还要提个小细节:你Db类的onUpgrade方法里表名拼错了,autiusm应该是autism,不然以后升级数据库时会因为找不到表而报错。
修复步骤
- 延迟Db的初始化时机:只声明Db变量,等到Fragment有可用Context时再初始化,比如在
onAttach或onViewCreated方法里。 - 修正Db类里的表名拼写错误。
- 额外添加一些优化点,比如输入校验、数据库资源释放,提升代码健壮性。
修改后的代码
1. 修正StartFragment类
package com.llmago.autism; import android.content.Context; import android.os.Bundle; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class StartFragment extends Fragment { private EditText edtName, edtAge, edtScore; private Button save; private Db db; // 只声明,不提前初始化 public StartFragment() { // Required empty public constructor } @Override public void onAttach(Context context) { super.onAttach(context); // 在这里初始化Db,此时Context已经确定可用 db = new Db(context); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_start, container, false); initUI(view); return view; } private void initUI(View view) { edtName = view.findViewById(R.id.name); edtAge = view.findViewById(R.id.age); edtScore = view.findViewById(R.id.result); save = view.findViewById(R.id.save); save.setOnClickListener(v -> btnSaveAction()); } private void btnSaveAction() { String name = edtName.getText().toString().trim(); String age = edtAge.getText().toString().trim(); String score = edtScore.getText().toString().trim(); // 先做输入校验,避免空数据插入 if(name.isEmpty() || age.isEmpty() || score.isEmpty()){ Toast.makeText(getActivity(), "请填写完整信息", Toast.LENGTH_SHORT).show(); return; } boolean result = db.insertData(name, age, score); if (result) { Toast.makeText(getActivity(), "保存成功", Toast.LENGTH_LONG).show(); // 保存后清空输入框,提升用户体验 edtName.setText(""); edtAge.setText(""); edtScore.setText(""); } else { Toast.makeText(getActivity(), "保存失败,请重试", Toast.LENGTH_LONG).show(); } } }
2. 修正Db类
package com.llmago.autism; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import androidx.annotation.Nullable; public class Db extends SQLiteOpenHelper { public static final String DATABASE_NAME = "autism.db"; private static final String TABLE_NAME = "autism"; // 用常量存储表名,避免拼写错误 public Db(@Nullable Context context) { super(context, DATABASE_NAME, null, 1); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + TABLE_NAME + "(" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT," + "age TEXT," + "score TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 修正表名拼写错误,同时使用常量更可靠 db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); } public boolean insertData(String name, String age, String score){ SQLiteDatabase sqLiteDatabase = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("name", name); contentValues.put("age", age); contentValues.put("score", score); long result = sqLiteDatabase.insert(TABLE_NAME, null, contentValues); sqLiteDatabase.close(); // 操作完成后关闭数据库,避免资源泄漏 return result != -1; } }
额外建议
- 优先用
onAttach(Context context)获取Context,这是Fragment依附到Activity时最早的回调,Context肯定可用; - 数据库操作完成后记得关闭连接,避免长期占用资源;
- 对用户输入做基础校验,既能提升体验,也能保证数据有效性;
- 用常量存储表名、列名,后期修改或维护时更方便,也能减少拼写错误。
内容的提问来源于stack exchange,提问作者Adnan Abou Elenein
相关产品推荐
相关产品推荐

