我得到了标题中描述的NullPointerException
,但我不知道如何使用错误消息中的信息来调试它。我如何知道什么是null,以及常见的原因是什么?
如果您看到类似java.lang.NullPointerException: Attempt to invoke virtual method '...' on a null object reference
的错误,此问题旨在帮助解决您的问题。
这也适用于以下所有类似错误:
java.lang.NullPointerException: Attempt to invoke interface method '...' on a null object reference
java.lang.NullPointerException: Attempt to read from field '...' on a null object reference
java.lang.NullPointerException: Attempt to read from null array
java.lang.NullPointerException: Attempt to get length of null array
注意:这是一个典型的自我回答问题,旨在为许多对Android上的NullPointerException
有疑问的用户提供一个单一的位置,其中包含Android特定的建议
有关此问题的非Android Java版本,或有关更多信息,请参阅What is a NullPointerException,以及如何修复它
什么是NullPointerException
首先,如果您不了解null
是什么,或者NullPointerException
是什么意思,请查看什么是NullPointerException,以及如何修复它?。这个答案的其余部分将假设你已经阅读了那篇文章。
如何调查原因
既然你已经了解了基本知识,你需要弄清楚你的错误在哪一行。看看什么是堆栈跟踪,以及我如何使用它来调试我的应用程序错误?有关如何做到这一点的信息。
一旦你知道错误在哪一行,接下来你需要做的就是弄清楚哪个变量是空的。错误消息将帮助您完成此操作。
如果您的错误看起来像(第一个...
可能是virtual
或interface
——哪个并不重要(:
java.lang.NullPointerException: Attempt to invoke ... method 'ReturnTypeOfMethod package.name.SomeClass.someMethod(...)' on a null object reference
这意味着您试图调用someMethod
的类型为package.name.SomeClass
的变量是null
。它还将列出方法的参数类型(如果有的话(,其中(...)
在示例中。
所以,如果你有这个代码:
MyClass myVariable = new MyClass();
String logMessage = "some other text: " + myVariable.toString() + someOtherVariable.method();
然后你得到这个错误消息:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.mypackagename.MyClass.toString()' on a null object reference
您知道myVariable
为null,因为这是MyClass
类型中唯一调用了toString()
的变量。java.lang.String
只是意味着toString()
返回一个String
。
如果错误为Attempt to read from field...
,则应用上述建议,但要查找读取字段引用(MyClass.someProperty
(,而不是调用方法(MyClass.someMethod()
(。
如果错误为Attempt to read from null array
,则在该行中查找按索引从数组中读取的任何内容(例如,someArrayVariable[i]
(。
如果错误为Attempt to get length of null array
,请查找对数组变量的.length
调用。
常见的根本原因和修复方法
findViewById,然后在活动/片段中设置视图
一个常见的问题是在实际设置视图之前调用findViewById。例如,在成员变量声明中调用它:
public class MyActivity extends Activity {
private Button submitButton = findViewById(R.id.submitButton);
// ... rest of Activity code ...
}
或在设置ContentView:之前
public class MyActivity extends Activity {
private Button submitButton;
public void onCreate(Bundle savedInstanceState) {
submitButton = findViewById(R.id.submitButton);
setContentView(R.layout.activity_main);
}
// ... rest of Activity code ...
}
这不起作用,因为findViewById
是在onCreate
方法(对于Activity
(或onCreateView(对于Fragment
(中调用setContentView
之前执行的。要解决此问题,请确保在setContentView
之后调用它。对于Fragment
s,您可以将代码放在onViewCreated
中,也可以确保在LayoutInflater.inflate
调用返回的View
上调用它。
布局ID/视图ID/视图不在布局中
有时问题是在给定布局中没有ID传递给findViewById的视图。仔细检查以确保您的setContentView
或LayoutInflater.inflate
调用具有正确的布局ID(与XML文件名匹配(,并且该布局XML文件中有一个具有该ID的视图(或<include>
s的视图(。