在 setContentView() 之前调用 findViewById() 会导致 NullPointerException 但并非总是如此?

Calling findViewById() before setContentView() causes NullPointerException but not always?

好吧,当我调用 findViewById() 访问按钮时,我得到一个 NullPointerException。我想我明白为什么我会收到这个错误,但是我脑子里有一些问题没有解决。 好吧,我想我收到这个错误是因为我将 findViewById() 调用从 onCreate() 方法内部移到了 class 范围,在所有方法之外。

现在我正在 onCreate() 方法之外初始化我的 ButtonEditText。 好吧,如果我理解正确的话,这是正在发生(空错误),因为 setContentView() 方法在 findViewById() 方法之后被调用,所以这就是它抛出异常的原因。

但是我不明白的是我在第二个 activity 中做了 同样的事情 并且工作了很好,没有任何空异常。我正在 onCreate() 方法之外初始化我的按钮等!

这确实让我有点困惑。如果能帮我解决这个问题,我将不胜感激。

第一个Activity

public class FirstActivity extends AppCompatActivity {
 
    private Button signUpButton= findViewById(R.id.lo_signUpButton);
    private Button loginButton = findViewById(R.id.lo_loginButton);
    private EditText username= findViewById(R.id.lo_usernameText);
    private EditText password= findViewById(R.id.lo_passwordText);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //set view
        setContentView(R.layout.activity_login);
        Log.i(TAG,"Create "+formatter.format(new Date()));

        //listeners
        signUpButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(LoginActivity.this, SignUpActivity.class));
                finish();
                }
        });

}

第二个Activity

public class SecondActivity extends AppCompatActivity {

    private EditText username = findViewById(R.id.su_username);
    private EditText password = findViewById(R.id.su_password);
    private TextView errorText= findViewById(R.id.su_error_msg);
    private Button signUpButton=findViewById(R.id.su_signupButton);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //set view
        setContentView(R.layout.activity_signup);
        Log.i(TAG,"Create");

        //listeners
        Button backButton = findViewById(R.id.su_backButton);
        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(SignUpActivity.this, LoginActivity.class));
                Log.i(TAG,"Going Back ");
                finish();
            }
        }); 

不能使用这个初始化:

public class SecondActivity extends AppCompatActivity {

    private Button signUpButton= findViewById(R.id.lo_signUpButton);
    //....
}

使用:

public class SecondActivity extends AppCompatActivity {

    private Button signUpButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //set view
        setContentView(R.layout.activity_signup)
        signUpButton= findViewById(R.id.lo_signUpButton);
        //...
    }
}

在第二个 Activity 中,您正在做一些不同的事情:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_signup);
    Button backButton = findViewById(R.id.su_backButton);
    //...
}

这是正确的,因为您在 setContentView 调用后使用 findViewById 方法在 onCreate 中声明并初始化了 backButton

在第一个 Activity 中,您使用 signUpButton.setOnClickListener 设置侦听器,但 signUpButton 未初始化(因为它在 onCreate 方法之外)

同样在第二个 Activity 中,OnCreate 方法中未使用其他错误初始化的按钮。

第二个activity,你没有使用过初始化错误的按钮,一旦使用也会出现异常

您使用了正确初始化的 backButton。

答案很简单。全局变量在调用 setContentView() 之前进行初始化,这意味着 findViewById() 将 return 为空。 findViewById() return 如果找到或为空,则为视图。由于您还没有调用 setContentView,它找不到您想要的视图。

FirstActivity和SecondActivity中的全局变量都是null。 FirstActivity 和 SecondActivity 之间的区别在于,您不访问 SecondActivity 中的任何全局变量。

您在 SecondActivity 中使用的唯一视图是调用 setContentView 后检索到的 backButton,因此当然不会抛出 NullPointerException。

始终将变量声明为全局变量并在 onCreate() 中对其进行初始化。更好的是,尽量避免全局变量并通过方法参数传递它们。