【问题标题】:Calling findViewById() from DialogFragment subclass gives NullPointerException从 DialogFragment 子类调用 findViewById() 会产生 NullPointerException
【发布时间】:2014-12-01 00:12:18
【问题描述】:

在下面的代码中,我尝试在单击按钮时显示一个基本对话框。该对话框显示一些需要显示一些文本。在我偶然发现一个错误后,我已经让它工作了,但我仍然对为什么会发生这个错误有疑问。 在 DialogFragmentSubclass.onCreateView() 中,我通过调用 findViewById(R.id.someIdValue) 获得对 TextView 的引用。这给了我 NullPointerException。但是,通过调用获取参考:

View v = inflate.inflate(someREsourceValue, container, fals);
TextView tv = (TextView) v.findViewById(R.id.someValue);

似乎可以解决问题。为什么这行得通,而另一个给我一个 NullPointerException? (完整代码见下文)

public class MainActivity extends Activity {
    DownloadImageDialogFragment myDialog;   

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

        // get reference to buttons
        Button buttonDownloadImage = (Button) findViewById(R.id.downloadImage);
        buttonDownloadImage.setText("Download new Image");

        // upon button click, show a Dialog
        buttonDownloadImage.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                FragmentTransaction ft = getFragmentManager().beginTransaction();

                myDialog = new DownloadImageDialogFragment();
                myDialog.show(ft, null);            
            }
        });

    }

    private class DownloadImageDialogFragment extends DialogFragment {              
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {

                View v = inflater.inflate(R.layout.fragment_dialog, container, false);
                // TextView tv = findViewById(R.id.dialogTextView); // this gives an error
                TextView tv = (TextView) v.findViewById(R.id.dialogTextView); // this works
                tv.setText("This is my dialog");
                return v;
            }
        }
}

这里是对话框的布局文件:

    <TextView 
        android:id="@+id/dialogTextView"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />

</LinearLayout>

【问题讨论】:

  • Fragment 只是一个 View 的占位符,您首先需要为 View 充气然后使用它。

标签: android view nullpointerexception findviewbyid dialogfragment


【解决方案1】:

当您调用findViewById() 时,您是从Activity 的内部类调用的,这就是该方法的来源。由于您的活动布局中不存在该视图 ID,因此您将获得 null。您的对话框片段必须先扩展其布局(如您所见),然后才能获得其中定义的视图。

【讨论】:

  • 感谢您的清晰解释。这很有道理!我完全忘记了内部类!
【解决方案2】:

要解释这一点,您确实需要了解什么是视图。

根据Androidwebsite的说法,

在屏幕上占据一个矩形区域,负责绘图和事件处理。 View 是小部件的基类,用于创建交互式 UI 组件(按钮、文本字段等)。 ViewGroup 子类是布局的基类,布局是包含其他视图(或其他 ViewGroup)并定义其布局属性的不可见容器。

本质上它是一个类。它扩展了 Object(java 基类)并实现了Drawable.Callback KeyEvent.Callback AccessibilityEventSource。如果您是 JAVA 新手,请阅读 this 以了解 implementsextends

现在,如果您了解findViewById(...) 函数,您将看到该函数返回一个View 对象。这不是 Textview 对象。所以只有你应该知道你需要做一些额外的步骤来使代码库工作。

现在,如果您深入研究并阅读TextView Android 页面,您会看到它扩展了 View 类。所以它继承了该类的所有内容。这基本上就是为什么您需要将“类型”传递给由findViewById(int id) 函数返回的视图。

最后,这一切都与您从哪里调用函数有关。如果你从一个没有定义视图的活动布局中调用你的函数,你会像你一样得到空指针异常。我相信在这种情况下,您是从具有自己的 xml 并且没有定义 textview 的子活动调用该函数。因此,您必须夸大拥有它的视图。添加TextView 标签即可。

【讨论】:

  • 感谢您的解释。您的回复中的以下句子是我不知道的:“最后,这一切都与您从哪里调用函数有关。如果您从没有定义 View 的 Activity 布局调用函数,您将获得 NULL像你一样的指针异常。”。现在这是有道理的,我确实更好地理解它。谢谢!
猜你喜欢
  • 2016-02-13
  • 1970-01-01
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多