工具栏和导航抽屉

5
我正在尝试在一个使用NavigationFragment的现有项目中包含Material Design。因此,我正在尝试使用Toolbar代替ActionBar。我按照这个指南进行操作,并将所有的getActionBar()替换为getSupportActionBar(),但我的应用程序始终在启动时崩溃。
activity_main.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.andreapivetta.mypckg.MainActivity">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <fragment
        android:id="@+id/navigation_drawer"
        android:name="com.andreapivetta.mypckg.NavigationDrawerFragment"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />


    <android.support.v7.widget.Toolbar
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimaryDark"/>

</android.support.v4.widget.DrawerLayout>

主活动

public class MainActivity extends ActionBarActivity
    implements NavigationDrawerFragment.NavigationDrawerCallbacks {

private NavigationDrawerFragment mNavigationDrawerFragment;
private CharSequence mTitle;
private static SharedPreferences mSharedPreferences;
static final String PREF_KEY_TWITTER_LOGIN = "isTwitterLogedIn";
static final String PREF_SELECTED_INDEX = "SELECTED_POSITION";
private ConnectionDetector connectionDetector;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    if (toolbar != null) {
        setSupportActionBar(toolbar);
    }

    mSharedPreferences = getSharedPreferences("MyPref", 0);
    setContentView(R.layout.activity_main);

    connectionDetector = new ConnectionDetector(this);

    startService(new Intent(getApplicationContext(), StartupService.class));
}

@Override
public void onResume() {
    super.onResume();

    if (isTwitterLoggedInAlready()) {
        mNavigationDrawerFragment = (NavigationDrawerFragment)
                getFragmentManager().findFragmentById(R.id.navigation_drawer);
        mTitle = getTitle();

        DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        setDrawerLeftEdgeSize(this, mDrawerLayout, 0.3f);

        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, mDrawerLayout);

        if (mSharedPreferences.getBoolean("FIRST_LAUNCH", true)) {
            mSharedPreferences.edit().putBoolean("FIRST_LAUNCH", false).apply();
        }
    } else {
        if (connectionDetector.isConnectingToInternet()) {
            Fragment fragment = new LoginFragment();
            FragmentManager fragmentManager = getSupportFragmentManager();

            fragmentManager.beginTransaction()
                    .replace(R.id.container, fragment).commit();
        } else {
            Toast.makeText(this, "internet connection required",
                    Toast.LENGTH_LONG).show();
        }
    }
}

@Override
public void onNavigationDrawerItemSelected(int position) {
    Fragment fragment;
    FragmentManager fragmentManager = getSupportFragmentManager();

    mSharedPreferences.edit().putInt(PREF_SELECTED_INDEX, position).apply();

    switch (position) {
        case 0:
            fragment = new MainFragment();
            fragmentManager.beginTransaction()
                    .replace(R.id.container, fragment).commit();
            setTitle(getResources().getString(R.string.app_name));
            break;
        case 1:
            ...
        case 2:
            ...
        case 3:
            ...
    }
}

@Override
public void setTitle(CharSequence title) {
    mTitle = title;
    getSupportActionBar().setTitle(mTitle);
}

public void restoreActionBar() {
    android.support.v7.app.ActionBar actionBar = getSupportActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setTitle(mTitle);
}
}

日志

10-28 14:20:29.085  32367-32367/com.andreapivetta.mypckg E/AndroidRuntime﹕ FATAL  EXCEPTION: main
Process: com.andreapivetta.mypckg, PID: 32367
java.lang.RuntimeException: Unable to start activity  ComponentInfo{com.andreapivetta.mypckg/com.andreapivetta.mypckg.MainActivity}: android.view.InflateException: Binary XML file line #20: Error inflating class fragment
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5001)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
 Caused by: android.view.InflateException: Binary XML file line #20: Error inflating class fragment
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
        at android.support.v7.app.ActionBarActivityDelegateBase.setContentView(ActionBarActivityDelegateBase.java:228)
        at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:102)
        at com.andreapivetta.mypckg.MainActivity.onCreate(MainActivity.java:56)
        at android.app.Activity.performCreate(Activity.java:5231)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
            at android.app.ActivityThread.access$800(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5001)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.app.ActionBar.setTitle(java.lang.CharSequence)' on a null object reference
        at com.andreapivetta.mypckg.MainActivity.setTitle(MainActivity.java:155)
        at com.andreapivetta.mypckg.MainActivity.onNavigationDrawerItemSelected(MainActivity.java:128)
        at com.andreapivetta.mypckg.NavigationDrawerFragment.selectItem(NavigationDrawerFragment.java:247)
        at com.andreapivetta.mypckg.NavigationDrawerFragment.onCreate(NavigationDrawerFragment.java:93)
        at android.app.Fragment.performCreate(Fragment.java:1678)
        at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:859)
        at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1040)
        at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1142)
        at android.app.Activity.onCreateView(Activity.java:4786)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:689)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
            at android.support.v7.app.ActionBarActivityDelegateBase.setContentView(ActionBarActivityDelegateBase.java:228)
            at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:102)
            at com.andreapivetta.mypckg.MainActivity.onCreate(MainActivity.java:56)
            at android.app.Activity.performCreate(Activity.java:5231)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
            at android.app.ActivityThread.access$800(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5001)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)

我做错了什么?


你需要展示你的代码,具体来说是 MainActivity.java:155 - tyczj
@tyczj 我刚刚添加了MainActivity最重要的部分。 - andrew
你在MainActivity中导入了哪个工具栏,是android.support.v7.widget.Toolbar吗? - MrEngineer13
3个回答

13

在你的onCreate方法中,在尝试访问工具栏视图之前,你从未设置内容。

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
    setSupportActionBar(toolbar);
}

mSharedPreferences = getSharedPreferences("MyPref", 0);
setContentView(R.layout.activity_main);

在您访问活动之前,您需要先设置其内容。

setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
    setSupportActionBar(toolbar);
}

mSharedPreferences = getSharedPreferences("MyPref", 0);

谢谢,我修改了这个并删除了ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeButtonEnabled(true); 从我的NavigationDrawer中,现在应用程序没有崩溃,但工具栏具有屏幕的高度:D - andrew
你不应该把工具栏放在你的DrawerLayout里面,它应该在外面。 - tyczj
你说得对。我现在无法测试我的代码,一旦我能够测试,我会将你的答案标记为正确的。 - andrew
当我使用AndroidAnnotations时,遇到了同样的问题。 必须定义一个方法并使用@AfterViews进行注释,以对使用@ViewById注入的视图进行初始化,因为这些字段不会在onCreate()方法中初始化。 - Alex Bitek

3

根据tyczy的建议,您需要在onCreate() 方法中更改您的代码。

您的布局还存在另一个问题。您在DrawerLayout中使用了3个视图,而您应该使用2个视图。

例如,您需要更改布局:

<android.support.v4.widget.DrawerLayout>

  <LinearLayout>

     <Toolbar..>

     <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

   </LinearLayout>

   <fragment
        android:id="@+id/navigation_drawer"
        android:name="com.andreapivetta.mypckg.NavigationDrawerFragment"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

</DrawerLayout>

是的,答案是正确的,但我已经感谢tyczj的评论而做到了。 - andrew

0

我曾经遇到过类似的问题。解决方法是将 NavigationDrawerFragment 中的 selectItem(..) 方法从 onCreateView() 移动到 onActivityCreated()

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    selectItem(mCurrentSelectedPosition);
    super.onActivityCreated(savedInstanceState);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接