为什么在 class 开头使用 findViewById(R.id.******) 初始化变量时,我的 Android 应用程序崩溃并出现 NullPointerException?

Why does my Android app crash with a NullPointerException when initializing a variable with findViewById(R.id.******) at the beginning of the class?

此代码,顶部的块已注释,运行s 成功:

public class MainActivity extends AppCompatActivity {

    /*
    EditText username = (EditText)findViewById(R.id.editText_Username);
    EditText password = (EditText)findViewById(R.id.editText_Password);
    TextView inputdata = (TextView)findViewById(R.id.textView_InputData);
    TextView welcome = (TextView)findViewById(R.id.textView_Welcome);
    Button login=(Button)findViewById(R.id.button_Login);
    Button anotherLogin=(Button)findViewById(R.id.button_Login_Another);
    */

    public void doLoginOnClick(View v)
    {
        String s1=username.getText().toString();
        inputdata.setText(s1);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fab); 
        fab.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    } 
 
}

我正在尝试使用

捕获组件的 ID

findViewById(R.id.***)

如您所见,我把这段代码放在了代码最开头的注释中。

EditText username = (EditText)findViewById(R.id.editText_Username);
EditText password = (EditText)findViewById(R.id.editText_Password);
TextView inputdata = (TextView)findViewById(R.id.textView_InputData);
TextView welcome = (TextView)findViewById(R.id.textView_Welcome);
Button login=(Button)findViewById(R.id.button_Login);
Button anotherLogin=(Button)findViewById(R.id.button_Login_Another);

如果我删除上面的注释并 运行 它(在模拟器和真实设备中),程序会立即崩溃,我很惊讶这里出了什么问题?

我什至尝试使用构造函数初始化相同的东西。

但是如果我把它放在里面 onCreate() 就不会崩溃?为什么?

我试图获取用户名和密码的信息并使用

将其显示到textView_Inputdata中的文本视图
EditText username = (EditText)findViewById(R.id.editText_Username);
EditText password = (EditText)findViewById(R.id.editText_Password);
TextView inputdata = (TextView)findViewById(R.id.textView_InputData);
inputdata.setText(username.getText.toString()+" "+password.getText.toString());

有更好或更简单的方法吗?

实例成员变量在实例本身初始化时被初始化。 findViewById()

太早了

onCreate() 之前,您的 activity 还没有 findViewById() 内部需要的 Window。在 setContentView() 之前(您应该在 onCreate() 中调用)也找不到视图。

因此在 onCreate()setContentView() 之后初始化您的视图引用。

添加此代码

 EditText username =  findViewById(R.id.editText_Username);
 EditText password = findViewById(R.id.editText_Password);
 TextView inputdata = findViewById(R.id.textView_InputData);
 TextView welcome = findViewById(R.id.textView_Welcome);
 Button login = findViewById(R.id.button_Login);
 Button anotherLogin = findViewById(R.id.button_Login_Another);

onCreate(); 

之后的方法
setContentView(R.layout.activity_main);

嘿,我看到您正在定义和初始化实例变量。 我所做的是定义实例变量 - EditText username 然后在 onCreate 方法中初始化它们 - username = (EditText) findViewById(R.id.editText_Username);

你不初始化实例变量的原因是因为元素在 onCreate 方法中的 setContentView 之后才准备好 - 我可能是错的,但我的最佳实践是定义实例变量,然后在onCreate方法中初始化它们

在设置 setContentView() 之前,您无法初始化视图 items.Because 届时 activity 视图将不存在。

将初始化保留在一个单独的方法中,并在将视图设置为 activity 后调用该方法。

您必须在 onCreate() 中的 setContentView() 之后调用 findViewById(),在此之前没有 UI/Layout 初始化这就是为什么您的 findViewById() 无法找到 ID并抛出 NullPointerException.

public class MainActivity extends AppCompatActivity {

    public void doLoginOnClick(View v){
        String s1 = username . getText ().toString();
        inputdata.setText(s1);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar =(Toolbar) findViewById (R.id.toolbar);
        setSupportActionBar(toolbar);

        EditText username =(EditText) findViewById (R.id.editText_Username);
        EditText password =(EditText) findViewById (R.id.editText_Password);
        TextView inputdata =(TextView) findViewById (R.id.textView_InputData);
        TextView welcome =(TextView) findViewById (R.id.textView_Welcome);
        Button login =(Button) findViewById (R.id.button_Login);
        Button anotherLogin =(Button) findViewById (R.id.button_Login_Another);

        FloatingActionButton fab =(FloatingActionButton) findViewById (R.id.fab);
        fab.setOnClickListener(new View . OnClickListener ()
        {
            @Override
            public void onClick(View view)
            {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
            }
        });
    }
}
  1. 在 onCreate() 方法之后初始化所有视图

  2. 详细了解 activity 生命周期 here

这样想 - 在您告诉 activity 使用哪个用户界面布局 (xml) 之前,它不知道从哪里获取这些视图。
您可以执行 setContentView(R.layout.your_xml) 来告诉 activity 使用哪个布局作为 activity 的用户界面。您将在 onCreate 回调中执行此操作,因为这是执行 'one-time activity level set up' 任务的回调。 setContentView() 就是这样一项任务。 执行此操作后,您可以开始访问布局文件中存在的视图 R.layout.your_xml.

onCreate(...) 
{
    ...
    setContentView(R.layout.your_xml) 
    // Ready to use the views from above xml. 
    findViewById(R.id.your_view) 
    ... 
}

setContentView()负责对activity的布局进行充气。如果在布局的 inflation 之前使用任何组件,它将崩溃并显示 NullPointerException.

 @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        setContentView(R.layout.activity_layout);
        username =  findViewById(R.id.editText_Username);
        password = findViewById(R.id.editText_Password);
        inputdata = findViewById(R.id.textView_InputData);
        welcome = findViewById(R.id.textView_Welcome);
        login = findViewById(R.id.button_Login);
        anotherLogin = findViewById(R.id.button_Login_Another);
            
    }

您仍然可以在 class 的开头声明变量,但您必须在 onCreate 中初始化它。

View Binding 将帮助您避免这些问题:

https://developer.android.com/topic/libraries/view-binding

或者在上面声明视图,在onCreate()中setContentView()之后初始化。

 public class MainActivity extends AppCompatActivity {

//Declare view on top
EditText username, password;
TextView inputdata,welcome;
Button login,notherLogin;


public void doLoginOnClick(View v)
{
    String s1=username.getText().toString();
    inputdata.setText(s1);
}

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //set view
    username =  findViewById(R.id.editText_Username);
    password = findViewById(R.id.editText_Password);
    inputdata = findViewById(R.id.textView_InputData);
    welcome = findViewById(R.id.textView_Welcome);
    login = findViewById(R.id.button_Login);
    anotherLogin = findViewById(R.id.button_Login_Another);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fab); 
    fab.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View view)
        {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });
} }