如何在onCreate中使用findViewById()而不返回null?

时间:2016-05-20 21:11:33

标签: android android-activity android-view oncreate findviewbyid

我不知道如何使用findViewById(R.id.nav_timetable);而不返回null并创建NPE。我尝试做的是默认加载TimetableFragment,然后人们可以使用抽屉转到其他片段。

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

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

    setupDrawer(toolbar);

    drawer.openDrawer(GravityCompat.START); // Opened this on first run so they know what's in it.

    // TODO Change this later to a home page and remove goToTimetablePage();
    // goToTimetablePage();
    goToFragmentFromNavMenuItem((MenuItem) findViewById(R.id.nav_timetable));
}

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
    // Handle navigation view item clicks here.

    goToFragmentFromNavMenuItem(menuItem);
    return true;
}

private void goToFragmentFromNavMenuItem(MenuItem menuItem) {
    // Create a new fragment and specify the fragment to show based on nav item clicked
    Fragment fragment = null;
    Class fragmentClass;

    switch (menuItem.getItemId()) {
        case R.id.nav_slideshow: // TODO fragmentClass = SlideshowFragment.class; break;
        case R.id.nav_share: // TODO fragmentClass = ShareFragment.class; break;
        case R.id.nav_timetable:
            fragmentClass = TimetableFragment.class;
            // goToTimetablePage();
            break;
        default:
            fragmentClass = TimetableFragment.class;
            // TODO Change this later to a home page:
            // TODO fragmentClass = HomeFragment.class; Remove "goToTimetablePage();"
    }


    //noinspection TryWithIdenticalCatches
    try {
        fragment = (Fragment) fragmentClass.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    FragmentManager fragmentManager = getSupportFragmentManager();

    fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();

    menuItem.setChecked(true);
    setTitle(menuItem.getTitle());
    drawer.closeDrawer(GravityCompat.START);
}

错误讯息:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gmail.gogobebe2.thedayahead/com.gmail.gogobebe2.thedayahead.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'int android.view.MenuItem.getItemId()' on a null object reference
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
  at android.app.ActivityThread.-wrap11(ActivityThread.java)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:148)
  at android.app.ActivityThread.main(ActivityThread.java:5417)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
  Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int android.view.MenuItem.getItemId()' on a null object reference
  at com.gmail.gogobebe2.thedayahead.MainActivity.goToNavFragment(MainActivity.java:123)
  at com.gmail.gogobebe2.thedayahead.MainActivity.onCreate(MainActivity.java:59)
  at android.app.Activity.performCreate(Activity.java:6237)
  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
  at android.app.ActivityThread.-wrap11(ActivityThread.java) 
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
  at android.os.Handler.dispatchMessage(Handler.java:102) 
  at android.os.Looper.loop(Looper.java:148) 
  at android.app.ActivityThread.main(ActivityThread.java:5417) 
  at java.lang.reflect.Method.invoke(Native Method) 
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

我尝试使用onCreateView方法,但由于某种原因它只是制作了stackoverflow消息。

编辑:这里是解决任何混淆的所有代码:https://github.com/gogobebe2/TheDayAhead

EDIT2:确保您不必担心goToTimetablePage()方法。目前尚未使用,我计划将其移至TimetableFragment片段。

EDIT3:我将方法名称更改为goToFragmentFromNavMenuItem(),以便更好地描述其清除操作的操作。我还想让你们知道onNavigationItemSelected(MenuItem menuItem)方法与goToFragmentFromNavMenuItem()方法完美配合,只是因为它在onCreate(Bundle savedInstanceState)内部使用时不起作用,因为findViewById(R.id.nav_timetable)一直返回null

此外,这是我制作的第一款Android应用程序,我在学习时有点学习。我甚至不知道昨晚的片段是什么,所以我对Android很新,请不要承担任何知识。

3 个答案:

答案 0 :(得分:1)

为了避免因 NPE 导致的崩溃,您可以在传递之前测试返回值是否为null:

MenuItem menuItem = (MenuItem) findViewById(R.id.nav_timetable);
if (menuItem != null) {
    goToNavFragment(menuItem);
}

无论如何,这无法解决您的问题,实际上findViewById(int)正在返回null,因为您正在搜索的视图ID不存在于您的活动布局中。

方法findViewById(),来自View类,您在this上调用它Activity(一个扩展View的类) ,在当前膨胀的布局中搜索视图ID(来自R)。

现在,如果您查看onCreate实施内容,就会发现您正在调用setContentViewMethod(R.layout.activity_main);这意味着您需要设置活动的布局,并将其从ID为activity_main的xml布局中删除。

这里最大的问题是您传递的布局(activity_main)不包含您正在寻找的ID。只需查看activity_main.xml布局文件,因为您可以看到没有ID为R.id.nav_timetable的对象。

活动一次只能加载一个布局活动文件。您仍然可以为菜单或特定视图对象(Spinner s,List等)加载其他布局文件。

最重要的是,您正在尝试检索MenuItem;要实现这一目标,您必须覆盖两个方法onCreateOptionsMenu()onOptionsItemSelected()

<小时/> onCreateOptionsMenu()就像它的名字所说的那样。它会创建您将要使用的选项菜单。在这里你可以勾勒你的行动,但你必须做的最重要的事情是膨胀菜单布局。如果没有这个,您将无法应用自定义菜单布局并使用findViewById

因此,在调用findViewById()之前,你应该这样做:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.your_menu_id, menu);

    // findViewById()

    return true;
}

当您选择先前创建的菜单中的项目时,将调用onOptionsItemSelected(),它将为您提供所选MenuItem的参数,您可以在此处实现菜单项单击操作。标准实现可以如下:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_one:
            doSomething()
            return true;
        case R.id.action_two:
            doSomethingElse();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

答案 1 :(得分:0)

不返回null的方法是为视图传递一个有效的Id。查看您的xml设计文件,并在函数中使用id,如下所示:

rootview.findViewById(R.id.your_id_here)

答案 2 :(得分:0)

由于您的问题不包含布局文件,我认为R.id.nav_timetable指的是片段的ID(并且是您的一部分布局)?如果是,则需要使用findFragmentById()(或FragmentManager)中的SupportFragmentManager代替findViewById()