【问题标题】:NullPointerException accessing views in onCreate()NullPointerException 在 onCreate() 中访问视图
【发布时间】:2014-07-02 10:57:56
【问题描述】:

这是 StackOverflow 上经常发布的问题的规范问题。

我正在学习教程。我使用向导创建了一个新活动。我在我的活动onCreate() 中尝试调用使用findViewById() 获得的Views 上的方法时得到NullPointerException

活动onCreate()

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

    View something = findViewById(R.id.something);
    something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}

布局 XML (fragment_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="packagename.MainActivity$PlaceholderFragment" >

    <View
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/something" />

</RelativeLayout>

【问题讨论】:

    标签: java android android-fragments nullpointerexception


    【解决方案1】:

    本教程可能已经过时,试图创建基于活动的 UI,而不是向导生成的代码首选的基于片段的 UI。

    视图在片段布局 (fragment_main.xml) 中,而不是在活动布局中 (activity_main.xml)。 onCreate() 在生命周期中太早,无法在活动视图层次结构中找到它,并返回 null。在 null 上调用方法会导致 NPE。

    首选的解决方案是将代码移动到片段onCreateView(),在膨胀的片段布局rootView上调用findViewById()

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      View rootView = inflater.inflate(R.layout.fragment_main, container,
          false);
    
      View something = rootView.findViewById(R.id.something); // not activity findViewById()
      something.setOnClickListener(new View.OnClickListener() { ... });
    
      return rootView;
    }
    

    附带说明,片段布局最终将成为活动视图层次结构的一部分,并且可以通过活动findViewById() 发现,但只有在片段事务运行后才能发现。在onCreate() 之后,待处理的片段事务在super.onStart() 中执行。

    【讨论】:

    • findViewById 部分应该在 onActivityCreated 中。
    • @Nepster 可以但不是必须的。
    • 有时活动还没有附加到片段。
    • @Nepster 这就是为什么在 rootView 上而不是在活动上调用 findViewById()
    【解决方案2】:

    既然您已经在fragment_main.xml 中声明了您的视图,请将那段代码移动到您在片段的onCreateView() 方法中获得NPE 的位置。 这应该可以解决问题。

    【讨论】:

      【解决方案3】:

      同意,这是一个典型的错误,因为人们在开始进行 Android 开发时通常并不真正了解 Fragment 的工作原理。为了避免混淆,我创建了一个简单的示例代码,最初发布在 Application is stopped in android emulator 上,但我也将其发布在这里。

      一个例子如下:

      public class ContainerActivity extends FragmentActivity implements ExampleFragment.Callback
      {
          @Override
          public void onCreate(Bundle saveInstanceState)
          {
              super.onCreate(saveInstanceState);
              this.setContentView(R.layout.activity_container);
              if (saveInstanceState == null)
              {               
                   getSupportFragmentManager().beginTransaction()
                      .add(R.id.activity_container_container, new ExampleFragment())
                      .addToBackStack(null)
                   .commit();
              }
              getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
              {
                  public void onBackStackChanged()
                  {
                      int backCount = getSupportFragmentManager().getBackStackEntryCount();
                      if (backCount == 0)
                      {
                          finish();
                      }
                  }
              });
          }
      
          @Override
          public void exampleFragmentCallback()
          {
              Toast.makeText(this, "Hello!", Toast.LENGTH_LONG).show();
          }
      }
      

      activity_container.xml:

      <?xml version="1.0" encoding="utf-8"?>
      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical" >
      
          <FrameLayout
              android:id="@+id/activity_container_container"
              android:layout_width="match_parent"
              android:layout_height="match_parent" />
      
      </RelativeLayout>
      

      示例片段:

      public class ExampleFragment extends Fragment implements View.OnClickListener
      {
          public static interface Callback
          {
              void exampleFragmentCallback();
          }
      
          private Button btnOne;
          private Button btnTwo;
          private Button btnThree;
      
          private Callback callback;
      
          @Override
          public void onAttach(Activity activity)
          {
              super.onAttach(activity);
              try
              {
                  this.callback = (Callback) activity;
              }
              catch (ClassCastException e)
              {
                  Log.e(this.getClass().getSimpleName(), "Activity must implement Callback interface.", e);
                  throw e;
              }
          }
      
          @Override
          public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
          {
              View rootView = inflater.inflate(R.layout.fragment_example, container, false);
      
              btnOne = (Button) rootView.findViewById(R.id.example_button_one);
              btnTwo = (Button) rootView.findViewById(R.id.example_button_two);
              btnThree = (Button) rootView.findViewById(R.id.example_button_three);
      
              btnOne.setOnClickListener(this);
              btnTwo.setOnClickListener(this);
              btnThree.setOnClickListener(this);
              return rootView;
          }
      
          @Override
          public void onClick(View v)
          {
              if (btnOne == v)
              {
                  Toast.makeText(getActivity(), "One.", Toast.LENGTH_LONG).show();
              }
              else if (btnTwo == v)
              {
                  Toast.makeText(getActivity(), "Two.", Toast.LENGTH_LONG).show();
              }
              else if (btnThree == v)
              {
                  callback.exampleFragmentCallback();
              }
          }
      }
      

      fragment_example.xml:

      <?xml version="1.0" encoding="utf-8"?>
      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent" >
      
              <Button
                  android:id="@+id/example_button_one"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_alignParentTop="true"
                  android:layout_centerHorizontal="true"
                  android:layout_marginTop="30dp"
                  android:text="@string/hello" 
                  android:layout_marginLeft="20dp"
                  android:layout_marginRight="20dp"/>
      
              <Button
                  android:id="@+id/example_button_two"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_alignLeft="@+id/example_button_one"
                  android:layout_alignRight="@+id/example_button_one"
                  android:layout_below="@+id/example_button_one"
                  android:layout_marginTop="30dp"
                  android:text="@string/hello" />
      
              <Button
                  android:id="@+id/example_button_three"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_alignLeft="@+id/example_button_two"
                  android:layout_alignRight="@+id/example_button_two"
                  android:layout_below="@+id/example_button_two"
                  android:layout_marginTop="30dp"
                  android:text="@string/hello" />
      
      </RelativeLayout>
      

      这应该是一个有效的例子,它展示了如何使用 Activity 来显示 Fragment,并处理该 Fragment 中的事件。以及如何与包含的 Activity 进行通信。

      【讨论】:

      • 本示例使用 android-support-v4 库来实现 FragmentActivity 和支持片段管理器。
      • 一个更完整的例子可以在stackoverflow.com/questions/24840509/…获得
      • 虽然你应该使用Otto进行通信而不是回调,并使用Butterknife注入视图。
      【解决方案4】:

      尝试 OnStart() 方法并使用

      View view = getView().findViewById(R.id.something);
      

      或在onStart()中使用getView().findViewById方法声明任何视图

      通过anyView.setOnClickListener(this);声明点击监听器

      【讨论】:

      • 对我来说这很有用,因为我试图访问片段的 onCreateView 中的同级视图,片段在 xml 中声明。 onCreateView 中的同级视图仍然为空,因为父级尚未完成充气,但在 onStart 中他们有:)
      【解决方案5】:

      在您的 activity_main.xml

      中添加以下内容
      <fragment
          android:id="@+id/myFragment"
          android:name="packagename.MainActivity$PlaceholderFragment"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" >
      </fragment>
      

      【讨论】:

        【解决方案6】:

        在上面发布的问题代码中存在问题: 您在 oncreate 方法中使用 R.layout.activity_main ,但 xml 文件名为 "fragment_main.xml" ,这意味着您正在尝试获取未显示的 fragment_main.xml 文件的视图,因此它给出了空指针异常。更改代码如下:

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.fragment_main);// your xml layout ,where the views are
        
            View something = findViewById(R.id.something);
            something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
        
            if (savedInstanceState == null) {
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.container, new PlaceholderFragment()).commit();
            }
        }
        

        【讨论】:

          【解决方案7】:

          您正在尝试访问 onCreate() 中的 UI 元素,但是现在访问它们还为时过早,因为可以在 onCreateView() 方法中创建片段视图。 并且onActivityCreated() 方法可以可靠地处理对它们的任何操作,因为在此状态下活动已完全加载。

          【讨论】:

            【解决方案8】:

            在调用 findViewById() onCreate()onCreateView() 方法后,我有相同的 NullPointerException 初始化监听器。

            但是当我使用onActivityCreated(Bundle savedInstanceState) {...} 时,它可以工作。所以,我可以访问GroupView 并设置我的监听器。

            希望对你有帮助。

            【讨论】:

              【解决方案9】:

              尝试将访问视图转移到片段的 onViewCreated 方法,因为有时当您尝试访问 onCreate 方法中的视图时,它们不会在导致空指针异常时呈现。

               @Override
              public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
                  super.onViewCreated(view, savedInstanceState);
                   View something = findViewById(R.id.something);
                   something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
              
                   if (savedInstanceState == null) {
                         getSupportFragmentManager().beginTransaction()
                          .add(R.id.container, new PlaceholderFragment()).commit();
                  }
               }
              

              【讨论】:

                【解决方案10】:

                视图“某物”在片段中而不是在活动中,因此您必须在片段类中访问它,而不是在活动中访问它

                在 PlaceholderFragment.class 中

                @Override
                public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
                View root = inflater.inflate(R.layout.fragment_main, container,
                  false);
                
                View something = root .findViewById(R.id.something);
                something.setOnClickListener(new View.OnClickListener() { ... });
                
                return root;
                }
                

                【讨论】:

                  【解决方案11】:

                  你必须记住重要的是: NullPointerException 发生在您已声明变量并尝试在为其赋值之前检索其值。

                  【讨论】:

                    【解决方案12】:

                    在使用或从片段调用视图时使用 onViewCreated() 方法。

                    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
                        super.onViewCreated(view, savedInstanceState)
                          View v = view.findViewById(R.id.whatever)
                    }
                    

                    【讨论】:

                      【解决方案13】:

                      几乎每个开发人员都在使用的最受欢迎的视图查找库。

                      ButterKnife

                      尽我所能,他们的答案足以解释用适当的方法寻找观点。但是,如果您是 android 开发人员并且每天经常编写代码,那么您可以使用黄油刀,它可以节省大量查找视图的时间并且您没有为其编写代码,只需 2-3 个步骤,您就可以在几毫秒内找到视图.

                      在应用级 gradle 中添加依赖:

                      implementation 'com.jakewharton:butterknife:8.8.1'
                      annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
                      

                      添加黄油刀插件:

                      File -> Settings -> plugins-> 
                      

                      然后搜索 Android ButterKnife Zelezny 并安装插件并重启你的工作室,你就完成了。

                      现在只需转到活动的 Oncreate 方法并右键单击您的 layout_name 并点击生成按钮并选择黄油刀注入选项,您的视图引用将自动创建,如下所述:

                          @BindView(R.id.rv_featured_artist)
                          ViewPager rvFeaturedArtist;
                          @BindView(R.id.indicator)
                          PageIndicator indicator;
                          @BindView(R.id.rv_artist)
                          RecyclerView rvArtist;
                          @BindView(R.id.nsv)
                          NestedScrollingView nsv;
                          @BindView(R.id.btn_filter)
                          Button btnFilter;
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-02-01
                        • 2016-04-05
                        • 2011-06-12
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多