问题描述
在项目中,需要创建一个自定义的dialog,然后在外部对于dialog的控件进行赋值,此时发现空指针异常。
如下所示
这个是dialog的java文件,很简单就是里面有一个textview,然后在外部向textview赋值。
public class MyDialog extends Dialog { private Context context; private TextView tipsView; public TimeConflictDialog(Context context) { super(context); this.context = context; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_time_conflict); initView(); } private void initView() { tips = findViewById(R.id.tv_tips); } public void setData(String str) { tips.setText(str); } } |
这里是外部调用的方式。
public class MyDialog extends Dialog { private Context context; private TextView tipsView; public TimeConflictDialog(Context context) { super(context); this.context = context; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_time_conflict); initView(); } private void initView() { tips = findViewById(R.id.tv_tips); } public void setData(String str) { tips.setText(str); } } |
这是外部创建,赋值并显示的代码
MyDialog dialog =new MyDialog(this); dialog.setData("111"); dialog.show(); |
此时会报空指针异常的情况。
原因分析
根据在setData调用控件的时候出现空指针异常,应该就是onCreate和setData的执行顺序的问题。setData的时候,onCreate中的控件还没有加载布局,自然控件指向null。接下来验证猜想。
此时点开dialog.show的源码,可以看到如下的源码。
public void show() { if (mShowing) { if (mDecor != null) { if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR); } mDecor.setVisibility(View.VISIBLE); } return; } mCanceled = false; if (!mCreated) { dispatchOnCreate(null); } else { // Fill the DecorView in on any configuration changes that // may have occured while it was removed from the WindowManager. final Configuration config = mContext.getResources().getConfiguration(); mWindow.getDecorView().dispatchConfigurationChanged(config); } onStart(); …… } |
首先会判断是否正在显示,接着判断是否已创建dialog,如果没有调用dispatchOnCreate,这个方法内部会调用onCreate。此时再回看我们之前的调用顺序,先调用了setData,再show,自然此时onCreate还没调用,所以才会导致空指针异常。
所以如果想要正常实现,需要先调用show方法,再调用setData。虽然我觉得有点不太合理,按理来说应该是数据全部赋值完毕,控件初始化完成后,再展示dialog。但是源码中是在show中创建dialog,所以只能这样实现。