来自 EditText 的 getText():是否有可能获得 'null'?

getText() from EditText: is it possible to get a 'null'?

我正在研究我正在编写的 Android 应用程序,并试图使我的代码完全符合 Android Studio 的 lint 建议。

我有以下发出警告的代码(省略了一些代码):

final EditText input = (EditText)view.findViewById(R.id.edit_text);
Button button        = (Button)view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String value = input.getText().toString();
        if (value == null || value.length() == 0) {

Android Studio 给我一个警告:

Condition 'value == null' is always false.

当我允许 Android Studio 为我 "fix" 解决问题时,它建议:

Simplify 'value == null' to false

代码则变为:

if (value.length() == 0) {

我查看了 Android 源代码 (http://www.grepcode.com),但我很困惑。 EditText 的文档说 "EditText is a thin veneer over TextView that configures itself to be editable." 然后, getText() 方法定义如下:

@Override
public Editable getText() {
    return (Editable) super.getText();
}

当我去 getText() 寻找 TextView("super")时,我看到了这个:

public CharSequence getText() {
    return mText;
}

TextViewsetText() 方法似乎不允许 null 值,因为这是该方法的开始:

private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen) {
    if (text == null) {
        text = "";
    }

默认构造函数也是这样启动的:

public TextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mText = "";

所以,看来 getText() 没有办法 return 一个 null 值,但是 this answer indicate that it is. The answers to this question 上的评论似乎也表明它有可能。

我想练习防御性编码,这就是为什么我从一开始就按照我的方式构建我的代码,但我不想做 null 检查一些不可能的事情成为 null。那么,在这种情况下,最佳做法是什么?

你可以使用 TextUtils.isEmpty(值);

final EditText input = (EditText)view.findViewById(R.id.edit_text);
Button button        = (Button)view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String value = input.getText().toString();
        if (TextUtils.isEmpty(value)) {
          // value is empty
        }else{
          // have value
        }

您可能会收到此警告,因为您的 value 不包含从 EditText#getText() return 编辑的内容(return 是 CharSequence),它取而代之的是 CharSequence#toString() 中的 return(return 是 String)。

toString() 调用非空 CharSequence 到 return 空应该是不可能的,这就是为什么 lint 警告您不需要空检查的原因。您应该改为对 EditText#getText() 的 return 进行空值检查。

换句话说,如果您的 input.getText() 为 null,则它在未调用 toString() 之前就已经失败,因此您的 null 检查将永远无法进行。

我认为 lint 检查告诉您的信息略有不同:

String value = input.getText().toString();
if (value == null || value.length() == 0) {

Condition 'value == null' is always false.

实际上,在这个 if 语句中,EditText.getText() 是否可以 return null 并不重要。因为如果它 return 为 null,那么 .toString() 甚至会在到达 if 语句之前引发 NullPointerException。因此,如果 if 语句完全可达,则值不能为空。

你可以翻遍 Android 源代码,也许你会发现 EditText 到 return null 是不可能的。如果是这种情况,那么如果您知道标准 EditText 在您的应用程序中,则可以忽略 lint 警告。

然而,在更一般的情况下,没有什么能阻止我将其粘贴在视图层次结构中:

public class EvilEditText extends EditText {
    // Constructors

    @Override
    public Editable getText() {
        return null;
    }
}

所以最安全的选择是重写您的代码以完全实现空安全:

Editable e = input.getText();
String value = (e == null ? null : e.toString());
if (TextUtils.isEmpty(value)) {  //hat tip to Deepak Goyal's answer. Could also use isEmpty(e)

表达式中的值

String value = input.getText().toString();

不会是null。 因为如果输入是 null,它将为方法调用 input.getText() 生成一个 NPE。因此下一条语句不会执行。如果你处理这个 NPE 类似

的东西
            String value = null;
            if (input!=null) {
                value = input.getText().toString();
            }
            if (value == null || value.length() == 0){

            }

那么你将不会得到那个指示。