在onCreate()执行前声明View致应用崩溃的解决方案咨询
解决Android Activity初始化前调用View相关方法导致的崩溃问题
嘿,我来帮你搞定这个崩溃问题!你遇到的java.lang.NullPointerException本质原因很明确:你在Activity的onCreate()方法执行之前就尝试初始化View和布局相关对象了——这时候Activity还没完成初始化,setContentView()都没调用,Activity的Window对象都还不存在,调用findViewById()或者getLayoutInflater()自然会返回null,触发空指针异常。
不过别担心,我们可以通过「延迟初始化全局变量」的方式解决,既保证这些View是全局可访问的(不会相互独立),又能避开错误的初始化时机。
修改后的完整代码
public class MainActivity extends AppCompatActivity { // 仅声明全局成员变量,不做初始化操作 public ConstraintLayout constraintLayout; LayoutInflater inflater; public View rectimage3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 在setContentView之后安全初始化全局变量 constraintLayout = (ConstraintLayout) findViewById(R.id.constraint_layout0); inflater = getLayoutInflater(); rectimage3 = inflater.inflate(R.layout.my_rectview, constraintLayout, false); final ImageView rectimage = (ImageView) findViewById(R.id.rectimage); // 设置监听器 rectimage.setOnTouchListener(new MySecOnTouchListener()); rectimage3.setOnTouchListener(new MyOnTouchListener()); constraintLayout.setOnDragListener(new MyDragListener()); } // 第一个矩形的触摸监听器 private final class MySecOnTouchListener implements View.OnTouchListener { @Override public boolean onTouch(View sview, MotionEvent motionEvent){ int action = motionEvent.getAction(); if(action == MotionEvent.ACTION_DOWN){ // 修复了原代码中多余的分号 rectimage3.setVisibility(View.VISIBLE); constraintLayout.addView(rectimage3); ClipData data = ClipData.newPlainText("", ""); View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(rectimage3); rectimage3.startDrag(data, shadowBuilder, rectimage3, 0); rectimage3.setVisibility(View.INVISIBLE); return true; } else{ return false; } } } // 可移动矩形的触摸监听器 private final class MyOnTouchListener implements View.OnTouchListener { @Override public boolean onTouch(View view, MotionEvent motionEvent){ int action = motionEvent.getAction(); if (action == MotionEvent.ACTION_DOWN) { ClipData data = ClipData.newPlainText("", ""); View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view); view.startDrag(data, shadowBuilder, view, 0); view.setVisibility(View.INVISIBLE); return true; } else { return false; } } } // 布局的拖拽监听器 class MyDragListener implements View.OnDragListener{ @Override public boolean onDrag(View v, DragEvent event) { View view = (View) event.getLocalState(); switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: view.setVisibility(View.VISIBLE); break; case DragEvent.ACTION_DRAG_LOCATION: view.setX(event.getX()-(view.getWidth()/2)); view.setY(event.getY()-(view.getHeight()/2)); break; case DragEvent.ACTION_DROP: break; } return true; } } }
关键说明和额外修复
- 延迟初始化的逻辑:把全局变量的初始化放在
setContentView()之后,此时Activity的View树已经构建完成,findViewById()和getLayoutInflater()都能正常获取到对象,避免空指针。同时变量保持public,内部监听器可以直接访问,保证View实例是同一个,不会出现相互独立的问题。 - 修复了隐藏逻辑错误:原代码中
MySecOnTouchListener的if(action == MotionEvent.ACTION_DOWN);末尾多了一个分号,这会导致后续代码块无论触摸动作是不是DOWN都会执行,我已经帮你去掉了这个分号。 - 生命周期规则:记住Android Activity的核心规则:所有依赖Activity上下文、View树的操作,必须在
onCreate()中setContentView()之后执行,或者在更靠后的生命周期方法(比如onStart())中执行,onCreate()是最适合初始化的时机。
内容的提问来源于stack exchange,提问作者Argos
相关产品推荐
相关产品推荐

