NullPointerException异常的FrameLayout.onMeasure() [英] NullPointerException in FrameLayout.onMeasure()

查看:471
本文介绍了NullPointerException异常的FrameLayout.onMeasure()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:我创建了一个Github的项目,崩溃在我的应用程序做了相同的方式。你可以找到它

编辑:我已经调试这一点,并尝试了各种变化,我才意识到原来的code我贴是不是真的有关,所以我删除它:

我有一个活动,可当用户按下3一个<$ 3种不同的片段 S开关C $ C> IconButton 的I已经插入到动作条中的自定义布局,像各种模式之间切换:

当我第一次启动该应用程序(已卸载的话),我默认为地球模式。环球剧场模式有几个片段一个 ViewPager ,大部分这些片段都是 android.support.v4.app.ListFragment 。我创建的所有8我的选项卡中的主要活动的onCreate方法。这工作正常,并妥善一切加载。

当我去档案模式(通过点击面对iconbutton),我可以登录到应用程序,看看我的个人资料。这也工作正常,一切都正确加载。

在我的再次按下APK 的从Android的工作室,因为我现在登录(节省preferences),它默认了我的朋友进模式(两个人牵着手)。我可以切换模式的配置文件,一切工作正常,但是当我切换到全球模式,它是在崩溃的Andr​​oid code:

  08-14 14:43:22.744 28804-29323 / com.trover E / AndroidRuntime:致命异常:主要
    工艺:com.trover,PID:28804
    显示java.lang.NullPointerException
            在android.widget.FrameLayout.onMeasure(FrameLayout.java:309)
            在android.view.View.measure(View.java:16497)
            在android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
            在com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:327)
            在android.view.View.measure(View.java:16497)
            在android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
            在android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            在com.android.internal.policy.impl.PhoneWindow $ DecorView.onMeasure(PhoneWindow.java:2291)
            在android.view.View.measure(View.java:16497)
            在android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1912)
            在android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1109)
            在android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1291)
            在android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:996)
            在android.view.ViewRootImpl $ TraversalRunnable.run(ViewRootImpl.java:5600)
            在android.view.Choreographer $ CallbackRecord.run(Choreographer.java:761)
            在android.view.Choreographer.doCallbacks(Choreographer.java:574)
            在android.view.Choreographer.doFrame(Choreographer.java:544)
            在android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.java:747)
            在android.os.Handler.handleCallback(Handler.java:733)
            在android.os.Handler.dispatchMessage(Handler.java:95)
            在android.os.Looper.loop(Looper.java:136)
            在android.app.ActivityThread.main(ActivityThread.java:5001)
            在java.lang.reflect.Method.invokeNative(本机方法)
            在java.lang.reflect.Method.invoke(Method.java:515)
            在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:785)
            在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
            在dalvik.system.NativeStart.main(本机方法)
 

在我已经做了两个重大变化的项目在过去两周:

  1. 在我已删除了ActionbarSherlock库。我本来希望能够去除support.v4库顺利,直到我意识到我需要它的ViewPager。
  2. 我从Eclipse中切换到Android工作室,其中包括将所有的文件到新的Andr​​oid工作室的结构。

今天早上,我重新安装了Eclipse和去点去除ActionbarSherlock之后,无法重新创建此崩溃。

我曾尝试

东西:

  • 在手动建设有摇篮的项目,并手动安装并运行它。当我做同样的步骤,它崩溃以同样的方式。
  • 通过调试运行这一点,并停止在崩溃。行309是这样的:

     如果(mMeasureAllChildren || child.getVisibility()!= GONE){
     

在这一点上,在code,孩子,但是,在调用 getChildCount()上线296返回值为2的我仍然不知道哪个说法实际上崩溃在这一点上的,没有定义值在任何变量,因为我通过他们在调试器中浏览。

  • 在登录时输入/输出,这是在溢出菜单项改变。当你点击 IconButton S上顶,我称之为 setBackgroundDrawable 的IconButtons设置黄色突出显示(或设置如果不是主动按钮了)。当我注释掉无论是在 onCreateOptionsMenu 的code和 setHighlightedIconButton的code()中,崩溃不再出现
  • 当我删除所有的片段从 ViewPager ,崩溃不再出现
  • 作为@kcoppock下面所提到的,它有可能成为我正在充气不当,一些地方。继他挂了一篇文章,我修改我的应用程序每次调用我在那里叫 inflater.inflate(R.layout.somelayout,空)来代替 inflater.inflate(R.layout.somelayout,viewGroupContainer,假的),除了在我创建选项卡上的自定义视图的情况下(我不知道的ViewGroup于母公司他们下),。在这种情况下,我手动设置LayoutParameters。

我完全不知所措,在这一点上,以什么,甚至尝试下。

更新:的更改应用到的总是的开始在全球模式prevents崩溃,所以它似乎有什么东西与交换机到全球模式,如果我们并没有开始使用它激活。

下面是我的code建选项卡为主要活动的viewPager:

  //我们已经创建布局之前先阅读该值了,还是onTabSelected将其设置回零
    最终的共享preferences preFS = getApplicationContext()。getShared preferences(
            常量preferences preFS_FILE,Context.MODE_PRIVATE)。
    布尔deniedLocationServices = prefs.getBoolean(常数preferences.LOCATION_SERVICES_DENIED,假的。);
    INT previousTab = prefs.getInt(常数preferences preVIOUS_TAB,0);

    的setContentView(R.layout.main_browse);

    mFragmentManager = getSupportFragmentManager();

    mActionBar = getActionBar();
    mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    //这三行隐藏Trover标志
    mActionBar.setDisplayHomeAsUpEnabled(假);
    mActionBar.setDisplayUseLogoEnabled(假);
    mActionBar.setIcon(新ColorDrawable(android.R.color.black));
    mActionBar.setCustomView(R.layout.action_bar_icons);
    mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME);
    最终诠释numTabs = 8;

    TabbedBrowsePagerTab []选项卡=新TabbedBrowsePagerTab [numTabs]

    标签[mAllTabPosition] = buildAllTab();
    标签[mWhatsHotTabPosition] = buildWhatsHotTab();
    标签[mWhatsNewTabPosition] = buildWhatsNewTab();
    标签[mJumpToTabPosition] = buildJumpToTab();
    标签[mFoodTabPosition] = buildFoodTab();
    标签[mOutdoorTabPosition] = buildOutdoorTab();
    标签[mArtTabPosition] = buildArtTab();
    标签[mLatestTabPosition] = buildLatestTab();

    mPagerAdapter =新TabbedBrowsePagerAdapter(这一点,制表符);
    mViewPager =(ViewPager)findViewById(R.id.pager);
    mViewPager.setAdapter(mPagerAdapter);

    mViewPager.setOnPageChangeListener(新ViewPager.SimpleOnPageChangeListener(){
        @覆盖
        公共无效onPageSelected(最终诠释位置){
            尝试 {
                mActionBar.setSelectedNavigationItem(位置);
            }赶上(最终IllegalStateException异常E){
                TroverApplication.logError(TAG,在PageChangeListener IllegalArgumentsException设置标签位置);
            }
        }
    });

    //建立在动作条的实际标签
    的for(int i = 0; I&LT; tabs.length;我++){
        mActionBar.addTab(mActionBar.newTab()
                .setTabListener(本));

        LayoutInflater充气= LayoutInflater.from(本);
        查看customView = inflater.inflate(R.layout.custom_action_bar_tabs,NULL);
        customView.setLayoutParams(新ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
        TextView的tabCustom =(TextView中)customView.findViewById(R.id.custom_action_bar_tab);
        tabCustom.setText(制表符[I] .getTabTitle());
        tabCustom.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
        tabCustom.setTypeface(TroverApplication.getDefaultFontBold());
        mActionBar.getTabAt(ⅰ).setCustomView(tabCustom);
    }

    //现在设置按钮监听那些图标
    mActionBar.getCustomView().findViewById(R.id.action_bar_friend_feed_button).setOnClickListener(this);
    。mActionBar.getCustomView()findViewById(R.id.action_bar_me_button).setOnClickListener(本);
    。mActionBar.getCustomView()findViewById(R.id.action_bar_nearby_button).setOnClickListener(本);

    mViewPager.setCurrentItem(previousTab);

    TroverLocationManager马槽= TroverLocationManager.get();
    如果(manger.isNetworkLocationEnabled()及!&安培;!deniedLocationServices){
        showLocationServicesDialog();
    }

    如果(AuthManager.get()。isAuthenticated()){
        mCurrentMode = Mode.NEWS_MODE; //&LT; -----如果我改变这GLOBE_MODE它不会崩溃
    } 其他 {
        mCurrentMode = Mode.GLOBE_MODE;
    }
    validateView();
 

下面是main_browse.xml布局:

 &LT; XML版本=1.0编码=UTF-8&GT?;
&LT; RelativeLayout的的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    机器人:layout_height =FILL_PARENT
    机器人:layout_width =FILL_PARENT&GT;

    &LT; android.support.v4.view.ViewPager
        机器人:ID =@ + ID /寻呼机
        机器人:layout_width =match_parent
        机器人:layout_height =match_parent/&GT;

    &LT;按钮
        机器人:ID =@ + ID / main_camera_button
        机器人:layout_width =WRAP_CONTENT
        机器人:layout_height =WRAP_CONTENT
        机器人:layout_alignParentBottom =真
        机器人:layout_alignParentRight =真
        机器人:layout_marginBottom =15dp
        机器人:layout_marginRight =15dp
        机器人:背景=@可绘制/ camera_floating/&GT;

&LT; / RelativeLayout的&GT;
 

下面是setHighlightedIconButton功能:

 私人无效setHighlightedIconButton(){
    的ImageButton按钮;
    查看iconContainer = mActionBar.getCustomView();

    PaintDrawable selectedBackground =新PaintDrawable(getResources()的getColor(R.color.trover_selected_icon_background)。);

    按钮=(的ImageButton)iconContainer.findViewById(R.id.action_bar_friend_feed_button);
    如果(mCurrentMode == Mode.NEWS_MODE){
        button.setBackgroundDrawable(selectedBackground);
        button.setClickable(假);
    } 其他 {
        button.setBackgroundDrawable(空);
        button.setClickable(真正的);
    }

    按钮=(的ImageButton)iconContainer.findViewById(R.id.action_bar_nearby_button);
    如果(mCurrentMode == Mode.GLOBE_MODE){
        button.setBackgroundDrawable(selectedBackground);
        button.setClickable(假);
    } 其他 {
        button.setBackgroundDrawable(空);
        button.setClickable(真正的);
    }

    按钮=(的ImageButton)iconContainer.findViewById(R.id.action_bar_me_button);
    如果(mCurrentMode == Mode.PROFILE_MODE){
        button.setBackgroundDrawable(selectedBackground);
        button.setClickable(假);
    } 其他 {
        button.setBackgroundDrawable(空);
        button.setClickable(真正的);
    }
}
 

这是validateView()函数调用它:

  / **
 *通过检查目前的方式和认证状态,处理不同的片段之间的过渡。
 *此功能可以处理被称为多次,并且总是试图做最少的工作可能
 * 每一次。
 * /
私人无效validateView(){
    invalidateOptionsMenu();
    setHighlightedIconButton();

    认证= AuthManager.get()isAuthenticated布尔()。

    开关(mCurrentMode){
        案例GLOBE_MODE:
            //注意 - 我们没有录制屏幕,因为这里的标签会做到这一点
            removeMeFragment();
            removeNewsFragment();
            removeOnboardingFragment();
            mViewPager.setVisibility(View.VISIBLE);
            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            mPagerAdapter.madeVisible();
            打破;
        案例NEWS_MODE:
            如果(M previousTabPosition == mJumpToTabPosition){
                InputMethodManager IMM =(InputMethodManager)getSystemService(
                        Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(mViewPager.getWindowToken(),0);
            }
            recordScreen(getCurrentModeTrackingString(),这一点);
            removeMeFragment();
            removeOnboardingFragment();
            如果(mNewsFeedFragment == NULL){
                mNewsFeedFragment = DiscoveryListFragment.newNewsFeedInstance();
                。mFragmentManager.beginTransaction()加(android.R.id.content,mNewsFeedFragment).commit();
            }
            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
            mViewPager.setVisibility(View.GONE);
            打破;
        案例PROFILE_MODE:
            如果(M previousTabPosition == mJumpToTabPosition){
                InputMethodManager IMM =(InputMethodManager)getSystemService(
                        Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(mViewPager.getWindowToken(),0);
            }
            如果(认证){
                recordScreen(getCurrentModeTrackingString(),这一点);
                removeNewsFragment();
                removeOnboardingFragment();
                如果(mProfileFragment == NULL){
                    mProfileFragment = UserDetailFragment.newMeInstance();
                    。mFragmentManager.beginTransaction()加(android.R.id.content,mProfileFragment).commit();
                }
            } 其他 {
                recordScreen(getCurrentModeTrackingString()+/上岗,这一点);
                removeMeFragment();
                removeNewsFragment();
                如果(mOnboardingFragment == NULL){
                    removeOnboardingFragment();
                    mOnboardingFragment =新OnboardingFragment();
                    。mFragmentManager.beginTransaction()加(android.R.id.content,mOnboardingFragment).commit();
                }
            }
            mViewPager.setVisibility(View.GONE);
            打破;
        默认:
            TroverApplication.logError(TAG,无效的模式!);
    }
}
 

下面是 onCreateOptionsMenu 的主要活动:

 公共布尔onCreateOptionsMenu(最后菜单菜单){
    MenuInflater充气= getMenuInflater();
    inflater.inflate(R.menu.menu,菜单);
    如果(!AuthManager.get()。isAuthenticated()){
        菜单项项= menu.findItem(R.id.menu_notifications);
        如果(项目!= NULL){
            item.setVisible(假);
        }
        项目= menu.findItem(R.id.menu_recommended_users);
        如果(项目!= NULL){
            item.setVisible(假);
        }
    }
    返回true;
}
 

这是 FrameLayout.onMeasure()功能的一部分,这是对Android的API 19源$ C ​​$ C在那里崩溃的一部分:

  @覆盖
保护无效onMeasure(INT widthMeasureSpec,诠释heightMeasureSpec){
    诠释计数= getChildCount(); &LT;  - 这是返回2

    最终布尔measureMatchParentChildren =
            MeasureSpec.getMode(widthMeasureSpec)!= MeasureSpec.EXACTLY ||
            MeasureSpec.getMode(heightMeasureSpec)= MeasureSpec.EXACTLY!;
    mMatchParentChildren.clear();

    INT了maxHeight = 0;
    INT了maxWidth = 0;
    INT的ChildState = 0;

    的for(int i = 0; I&LT;计数;我++){
        最后查看孩子= getChildAt(我);
        如果(mMeasureAllChildren || child.getVisibility()=不见了!){&LT;  - 崩溃发生在这里
            measureChildWithMargins(儿童,widthMeasureSpec,0,heightMeasureSpec,0);
            最后的LayoutParams LP =(的LayoutParams)child.getLayoutParams();
            =了maxWidth Math.max(了maxWidth,
                    child.getMeasuredWidth()+ lp.leftMargin + lp.rightMargin);
            =了maxHeight Math.max(了maxHeight,
                    child.getMeasuredHeight()+ lp.topMargin + lp.bottomMargin);
            的ChildState = combineMeasuredStates(的ChildState,child.getMeasuredState());
            如果(measureMatchParentChildren){
                如果(lp.width == LayoutParams.MATCH_PARENT ||
                        lp.height == LayoutParams.MATCH_PARENT){
                    mMatchParentChildren.add(子);
                }
            }
        }
    }
 

解决方案

我结束了对申请一个AOSP错误为这一个:

HTTPS://$c$c.google。 COM / P /安卓/问题/详细信息?ID = 75056

(非常简洁)反应,我到了那里指出,在 ViewPager.onMeasure()功能,它会尝试执行任何未决的片段交易。不幸的是,它听起来就像另一个片段我的显示/隐藏会干扰这一进程,并导致NPE。

他们鼓励的解决办法是我的电话 FragmentManager.executePendingTransactions()我的 validateView()功能,presumably敲定片段交易我致力于使 viewPager 不影响他们。

Edit: I've created a Github project that crashes in the exact same way as my app does. You can find it here

Edit: As I've debugged this and tried various changes, I realized the original code I posted wasn't really relevant, so I removed it:

I have an Activity that can switch between 3 different Fragments when the user pushes one of 3 IconButtons I have inserted into the ActionBar in a custom layout, like switching between various modes:

When I first launch the app (having uninstalled it), I'm defaulted to the Globe mode. The Globe mode has several fragments in a ViewPager, most of these fragments are subclasses of the android.support.v4.app.ListFragment. I am creating all 8 of my tabs in the main Activity's onCreate method. This works as expected, and everything loads properly.

When I go to the "Profile" mode (by clicking on the Face iconbutton), I can log into the app, and see my profile. This also works as expected, everything is loading properly.

When I push the APK again from Android Studio, since I am now logged in (saved Preferences), it defaults me to the "friend feed" mode (the two people holding hands). I can switch modes to the Profile, and everything works as expected, but when I switch to the Globe mode, it is crashing in Android code:

08-14 14:43:22.744  28804-29323/com.trover E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.trover, PID: 28804
    java.lang.NullPointerException
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:309)
            at android.view.View.measure(View.java:16497)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
            at com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:327)
            at android.view.View.measure(View.java:16497)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2291)
            at android.view.View.measure(View.java:16497)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1912)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1109)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1291)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:996)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5600)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
            at android.view.Choreographer.doCallbacks(Choreographer.java:574)
            at android.view.Choreographer.doFrame(Choreographer.java:544)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5001)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
            at dalvik.system.NativeStart.main(Native Method)

In the past two weeks I have made two major changes to the project:

  1. I have removed the ActionbarSherlock library. I originally was hoping to remove the support.v4 library as well until I realized I needed it for the ViewPager.
  2. I switched from Eclipse to Android Studio, which included moving all of the files to the new Android Studio structure.

This morning I re-installed Eclipse and went to the point right after removing ActionbarSherlock, and could not recreate this crash.

Things I have tried:

  • Manually building the project with Gradle, and manually installing it and running it. When I do the same steps, it crashes in the same way.
  • Running this through the debugger, and stopping at the crash. Line 309 is the following:

        if (mMeasureAllChildren || child.getVisibility() != GONE) {
    

At this point in the code, child is null, however, the call to getChildCount() on line 296 is returning a value of 2. I still have no idea which View is actually crashing at this point, there is no defining value in any of the variable as I browse through them in the debugger.

  • When you log in/out, items that are in the overflow menu are changed. When you click on the IconButtons on the top, I call setBackgroundDrawable on the IconButtons to set the yellow highlight (or set null if it's not the active button anymore). When I comment out both the code in onCreateOptionsMenu and the code in setHighlightedIconButton(), the crash no longer occurs
  • When I remove all of the fragments from the ViewPager, the crash no longer occurs
  • As @kcoppock mentioned below, it could likely be that I'm improperly inflating something somewhere. Following the article he linked, I modified every call in my app where I was calling inflater.inflate(R.layout.somelayout, null) instead to inflater.inflate(R.layout.somelayout, viewGroupContainer, false), except in the case where I am creating custom views on the tabs (where I don't know the viewGroup to parent them under). In that case I'm manually setting LayoutParameters.

I'm completely at a loss at this point as to what to even try next.

update: Changing the app to always start in the Globe Mode prevents the crash, so it seems to be something with the switch to the Globe Mode if we didn't start with it active.

Here is my code to build the Tabs for the main Activity's viewPager:

    // We HAVE to read this value out before creating the layout, or onTabSelected will set it back to zero
    final SharedPreferences prefs = getApplicationContext().getSharedPreferences(
            Const.Preferences.PREFS_FILE, Context.MODE_PRIVATE);
    boolean deniedLocationServices = prefs.getBoolean(Const.Preferences.LOCATION_SERVICES_DENIED, false);
    int previousTab = prefs.getInt(Const.Preferences.PREVIOUS_TAB, 0);

    setContentView(R.layout.main_browse);

    mFragmentManager = getSupportFragmentManager();

    mActionBar = getActionBar();
    mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // these three lines hide the 'Trover' logo
    mActionBar.setDisplayHomeAsUpEnabled(false);
    mActionBar.setDisplayUseLogoEnabled(false);
    mActionBar.setIcon(new ColorDrawable(android.R.color.black));
    mActionBar.setCustomView(R.layout.action_bar_icons);
    mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME);
    final int numTabs = 8;

    TabbedBrowsePagerTab[] tabs = new TabbedBrowsePagerTab[numTabs];

    tabs[mAllTabPosition] = buildAllTab();
    tabs[mWhatsHotTabPosition] = buildWhatsHotTab();
    tabs[mWhatsNewTabPosition] = buildWhatsNewTab();
    tabs[mJumpToTabPosition] = buildJumpToTab();
    tabs[mFoodTabPosition] = buildFoodTab();
    tabs[mOutdoorTabPosition] = buildOutdoorTab();
    tabs[mArtTabPosition] = buildArtTab();
    tabs[mLatestTabPosition] = buildLatestTab();

    mPagerAdapter = new TabbedBrowsePagerAdapter(this, tabs);
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mPagerAdapter);

    mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(final int position) {
            try {
                mActionBar.setSelectedNavigationItem(position);
            } catch (final IllegalStateException e) {
                TroverApplication.logError(TAG, "IllegalArgumentsException setting tab position in PageChangeListener");
            }
        }
    });

    // Build the actual tabs on the actionbar
    for (int i = 0; i < tabs.length; i++) {
        mActionBar.addTab(mActionBar.newTab()
                .setTabListener(this));

        LayoutInflater inflater = LayoutInflater.from(this);
        View customView = inflater.inflate(R.layout.custom_action_bar_tabs, null);
        customView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        TextView tabCustom = (TextView) customView.findViewById(R.id.custom_action_bar_tab);
        tabCustom.setText(tabs[i].getTabTitle());
        tabCustom.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
        tabCustom.setTypeface(TroverApplication.getDefaultFontBold());
        mActionBar.getTabAt(i).setCustomView(tabCustom);
    }

    // Now set up the button listeners for those icons
    mActionBar.getCustomView().findViewById(R.id.action_bar_friend_feed_button).setOnClickListener(this);
    mActionBar.getCustomView().findViewById(R.id.action_bar_me_button).setOnClickListener(this);
    mActionBar.getCustomView().findViewById(R.id.action_bar_nearby_button).setOnClickListener(this);

    mViewPager.setCurrentItem(previousTab);

    TroverLocationManager manger = TroverLocationManager.get();
    if (!manger.isNetworkLocationEnabled() && !deniedLocationServices) {
        showLocationServicesDialog();
    }

    if (AuthManager.get().isAuthenticated()) {
        mCurrentMode = Mode.NEWS_MODE; // <----- if I change this to GLOBE_MODE it doesn't crash
    } else {
        mCurrentMode = Mode.GLOBE_MODE;
    }
    validateView();

Here is the main_browse.xml layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent" >

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/main_camera_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="15dp"
        android:layout_marginRight="15dp"
        android:background="@drawable/camera_floating" />

</RelativeLayout>

Here is the setHighlightedIconButton function:

private void setHighlightedIconButton() {
    ImageButton button;
    View iconContainer = mActionBar.getCustomView();

    PaintDrawable selectedBackground = new PaintDrawable(getResources().getColor(R.color.trover_selected_icon_background));

    button = (ImageButton) iconContainer.findViewById(R.id.action_bar_friend_feed_button);
    if (mCurrentMode == Mode.NEWS_MODE) {
        button.setBackgroundDrawable(selectedBackground);
        button.setClickable(false);
    } else {
        button.setBackgroundDrawable(null);
        button.setClickable(true);
    }

    button = (ImageButton) iconContainer.findViewById(R.id.action_bar_nearby_button);
    if (mCurrentMode == Mode.GLOBE_MODE) {
        button.setBackgroundDrawable(selectedBackground);
        button.setClickable(false);
    } else {
        button.setBackgroundDrawable(null);
        button.setClickable(true);
    }

    button = (ImageButton) iconContainer.findViewById(R.id.action_bar_me_button);
    if (mCurrentMode == Mode.PROFILE_MODE) {
        button.setBackgroundDrawable(selectedBackground);
        button.setClickable(false);
    } else {
        button.setBackgroundDrawable(null);
        button.setClickable(true);
    }
}

And this is the validateView() function which calls it:

/**
 * Handles transitions between different fragments by checking the current mode and authentication state.
 * This function can handle being called multiple times, and will always try to do the least work possible
 * each time.
 */
private void validateView() {
    invalidateOptionsMenu();
    setHighlightedIconButton();

    boolean authenticated = AuthManager.get().isAuthenticated();

    switch(mCurrentMode) {
        case GLOBE_MODE:
            // Note - we don't record a screen here because the tabs will do that
            removeMeFragment();
            removeNewsFragment();
            removeOnboardingFragment();
            mViewPager.setVisibility(View.VISIBLE);
            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            mPagerAdapter.madeVisible();
            break;
        case NEWS_MODE:
            if (mPreviousTabPosition == mJumpToTabPosition) {
                InputMethodManager imm = (InputMethodManager) getSystemService(
                        Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
            }
            recordScreen(getCurrentModeTrackingString(), this);
            removeMeFragment();
            removeOnboardingFragment();
            if (mNewsFeedFragment == null) {
                mNewsFeedFragment = DiscoveryListFragment.newNewsFeedInstance();
                mFragmentManager.beginTransaction().add(android.R.id.content, mNewsFeedFragment).commit();
            }
            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
            mViewPager.setVisibility(View.GONE);
            break;
        case PROFILE_MODE:
            if (mPreviousTabPosition == mJumpToTabPosition) {
                InputMethodManager imm = (InputMethodManager) getSystemService(
                        Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
            }
            if (authenticated) {
                recordScreen(getCurrentModeTrackingString(), this);
                removeNewsFragment();
                removeOnboardingFragment();
                if (mProfileFragment == null) {
                    mProfileFragment = UserDetailFragment.newMeInstance();
                    mFragmentManager.beginTransaction().add(android.R.id.content, mProfileFragment).commit();
                }
            } else {
                recordScreen(getCurrentModeTrackingString() + "/onboarding", this);
                removeMeFragment();
                removeNewsFragment();
                if (mOnboardingFragment == null) {
                    removeOnboardingFragment();
                    mOnboardingFragment = new OnboardingFragment();
                    mFragmentManager.beginTransaction().add(android.R.id.content, mOnboardingFragment).commit();
                }
            }
            mViewPager.setVisibility(View.GONE);
            break;
        default:
            TroverApplication.logError(TAG, "Invalid mode!");
    }
}

Here is the onCreateOptionsMenu for the main Activity:

public boolean onCreateOptionsMenu(final Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    if (!AuthManager.get().isAuthenticated()) {
        MenuItem item = menu.findItem(R.id.menu_notifications);
        if (item != null) {
            item.setVisible(false);
        }
        item = menu.findItem(R.id.menu_recommended_users);
        if (item != null) {
            item.setVisible(false);
        }
    }
    return true;
}

This is the part of the FrameLayout.onMeasure() function that is part of the Android API 19 source code where it is crashing:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int count = getChildCount();  <-- this is returning 2

    final boolean measureMatchParentChildren =
            MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
            MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
    mMatchParentChildren.clear();

    int maxHeight = 0;
    int maxWidth = 0;
    int childState = 0;

    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (mMeasureAllChildren || child.getVisibility() != GONE) { <-- crash happens here
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
            maxWidth = Math.max(maxWidth,
                    child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
            maxHeight = Math.max(maxHeight,
                    child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
            childState = combineMeasuredStates(childState, child.getMeasuredState());
            if (measureMatchParentChildren) {
                if (lp.width == LayoutParams.MATCH_PARENT ||
                        lp.height == LayoutParams.MATCH_PARENT) {
                    mMatchParentChildren.add(child);
                }
            }
        }
    }

解决方案

I ended up filing a bug against AOSP for this one:

https://code.google.com/p/android/issues/detail?id=75056

The (rather terse) response that I got there indicated that in the ViewPager.onMeasure() function it tries to execute any pending Fragment transactions. Unfortunately it sounds like my showing/hiding of the other fragments are interfering with this process and causing the NPE.

The workaround they encouraged was for me to call FragmentManager.executePendingTransactions() at the end of my validateView() function, presumably to finalize the fragment transactions I've committed so that the viewPager isn't affected by them.

这篇关于NullPointerException异常的FrameLayout.onMeasure()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆