从独立AlertDialog启动Activity时触发java.lang.NullPointerException问题排查
咱们先聚焦崩溃堆栈里的核心错误:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
这个错误直接指向LaunchBill.java第18行创建Intent的代码——因为传入的Context是null,导致Intent初始化时调用getPackageName()失败。咱们一步步揪出问题根源:
第一个坑:mContext根本没初始化
你在YallDoneDialog里声明了private Context mContext;,但从头到尾都没给它赋值!所以当你创建LaunchBill实例时,第一个参数mContext是个空对象,这直接导致后续Intent创建时炸了。
第二个坑:手动new Activity是绝对错误的操作
你在确认按钮的点击事件里写了MenuActivity m = new MenuActivity();——这可是Android开发的大忌!Activity的生命周期完全由系统管理,手动new出来的实例根本没有绑定系统的上下文环境,调用它的方法(比如getResName())不仅可能拿不到正确数据,还可能引发更多NPE。
现在来修复这些问题
第一步:修正YallDoneDialog的确认按钮逻辑
去掉手动创建MenuActivity的代码,改用正确的方式获取宿主Activity的实例(前提是弹出这个Dialog的宿主是MenuActivity),同时直接用getActivity()作为上下文传递给LaunchBill:
@Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage(R.string.done) .setTitle(R.string.done_title) .setPositiveButton(R.string.y, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // 先判断宿主Activity是不是MenuActivity,避免类型转换错误 if (getActivity() instanceof MenuActivity) { MenuActivity menuActivity = (MenuActivity) getActivity(); String resName = menuActivity.getResName(); // 直接用getActivity()作为上下文,不需要未初始化的mContext LaunchBill l = new LaunchBill(getActivity()); l.LaunchTheDuckingBill(resName); } dismiss(); } }) .setNegativeButton(R.string.n, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dismiss(); } }); return builder.create(); }
第二步:简化LaunchBill类(可选但推荐)
其实LaunchBill里的mActivity参数完全多余,启动Activity只需要Context就够了,咱们把它简化一下:
import android.content.Context; import android.content.Intent; public class LaunchBill { private Context mContext; public LaunchBill(Context mContext){ this.mContext = mContext; } public void LaunchTheDuckingBill(String resName){ Intent intent = new Intent(mContext, BillActivity.class); intent.putExtra("resName", resName); // 额外处理:如果Context不是Activity,需要添加FLAG_ACTIVITY_NEW_TASK if (!(mContext instanceof android.app.Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } mContext.startActivity(intent); } }
最后再提两个注意点
- 一定要确保
BillActivity已经在AndroidManifest.xml里注册了,不然就算修复了NPE,启动Activity还是会失败。 - 如果
resName不是来自宿主Activity,建议通过newInstance方法把数据传递到DialogFragment里,不要直接依赖宿主Activity的类型,这样代码更健壮。
内容的提问来源于stack exchange,提问作者Siku M.

