NullPointerException in FrameLayout.onMeasure ()

Bearbeiten: Ich habe ein Github-Projekt erstellt, das genau so stürzt wie meine App. Sie können es hier finden

Bearbeiten: Wie ich dieses Problem getan habe und verschiedene Änderungen ausprobiert habe, habe ich erkannt, dass der ursprüngliche Code, den ich gepostet habe, nicht wirklich relevant war, also habe ich ihn entfernt:

  • Wie die "FBReader" die Paginierung von HTML-Dateien in epub machen
  • Android Studio kann keine Projekte öffnen
  • Facebook Login-Taste: bewerben Sie benutzerdefinierten Stil
  • Smack "Muss einen lokalen (User) JID Set" Fehler haben
  • Kann keine Jarlist-Cache-Datei schreiben, während sie ein Android-Projekt erstellen
  • Android-Layout Layout scrollbar, wenn die Soft-Tastatur öffnen, aber nicht verschieben es nach oben
  • Ich habe eine Activity , die zwischen 3 verschiedenen Fragment s wechseln kann, wenn der Benutzer eine von 3 IconButton s schiebt, die ich in die ActionBar in einem benutzerdefinierten Layout eingefügt habe, wie das Umschalten zwischen verschiedenen Modi:

    Bildbeschreibung hier eingeben

    Wenn ich zum ersten Mal die App starten (nachdem ich es deinstalliert habe), bin ich auf den Globe-Modus eingestellt. Der Globe-Modus hat mehrere Fragmente in einem ViewPager , die meisten dieser Fragmente sind Unterklassen der android.support.v4.app.ListFragment . Ich schaffe alle 8 meiner Tabs in der Main Activity OnCreate Methode. Das funktioniert wie erwartet, und alles lädt richtig.

    Wenn ich in den "Profil" -Modus gehe (durch Anklicken der Face Icon-Taste), kann ich mich bei der App anmelden und mein Profil sehen. Das funktioniert auch wie erwartet, alles wird richtig geladen.

    Wenn ich die APK wieder aus Android Studio schiebe , da ich jetzt angemeldet bin (gespeicherte Einstellungen), defauliert es mich auf den "Freund-Feed" -Modus (die beiden Leute, die Hände halten). Ich kann die Modi in das Profil umschalten, und alles funktioniert wie erwartet, aber wenn ich in den Globe-Modus wechsle, stürzt es im Android-Code ab:

     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 den vergangenen zwei Wochen habe ich zwei wesentliche Änderungen an dem Projekt gemacht:

    1. Ich habe die ActionbarSherlock-Bibliothek entfernt. Ich hatte ursprünglich gehofft, die support.v4 Bibliothek zu entfernen, bis ich merkte, dass ich es für den ViewPager benötigte.
    2. Ich wechselte von Eclipse zu Android Studio, die das Verschieben aller Dateien in die neue Android Studio-Struktur beinhaltete.

    Heute morgen habe ich Eclipse neu installiert und ging nach dem Entfernen von ActionbarSherlock auf den Punkt und konnte diesen Absturz nicht neu erstellen.

    Dinge, die ich versucht habe:

    • Manuelles Erstellen des Projekts mit Gradle und manuelles Installieren und Ausführen. Wenn ich die gleichen Schritte mache, stürzt es auf die gleiche Weise ab.
    • Laufen dies durch den Debugger und stoppen beim Absturz. Zeile 309 ist die folgende:

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

    An diesem Punkt im Code ist das child null , aber der Aufruf von getChildCount() auf Zeile 296 gibt einen Wert von 2 zurück. Ich habe noch keine Ahnung, welche View eigentlich an diesem Punkt abstürzt , es gibt keinen definierenden Wert in jedem Der Variablen, wie ich sie im Debugger durchsuche.

    • Wenn Sie sich ein- oder ausloggen, werden die Elemente, die sich im Überlaufmenü befinden, geändert. Wenn du auf die IconButton s auf die Oberseite setBackgroundDrawable , rufe ich setBackgroundDrawable auf die IconButtons an, um das gelbe Highlight einzustellen (oder null wenn es nicht mehr die aktive Taste ist). Wenn ich den Code in onCreateOptionsMenu und den Code in setHighlightedIconButton() , tritt der Absturz nicht mehr auf
    • Wenn ich alle Fragmente aus dem ViewPager , tritt der Absturz nicht mehr auf
    • Als @kcoppock unten erwähnt, könnte es wahrscheinlich sein, dass ich falsch etwas irgendwo aufblasen. Nach dem Artikel, den er verknüpft, habe ich jeden Anruf in meiner App geändert, wo ich inflater.inflate(R.layout.somelayout, null) anstatt zu inflater.inflate(R.layout.somelayout, viewGroupContainer, false) , außer in dem Fall Wo ich kundenspezifische Ansichten auf den Tabs schreibe (wo ich die ViewGroup nicht kenne, um sie zu unterwerfen). In diesem Fall setze ich manuell LayoutParameter ein.

    Ich bin an diesem Punkt völlig verzweifelt, was auch immer als nächstes zu versuchen

    Update: Das Ändern der App, um immer im Globe-Modus zu starten, verhindert den Absturz, also scheint es etwas mit dem Umstieg auf den Globe-Modus zu sein, wenn wir nicht damit aktiv sind.

    Hier ist mein Code, um die Tabs für die main Activity's viewPager zu bauen:

      // 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(); 

    Hier ist das 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> 

    Hier ist die setHighlightedIconButton-Funktion:

     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); } } 

    Und das ist die validateView () – Funktion, die es aufruft:

     /** * 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!"); } } 

    Hier ist das onCreateOptionsMenu für die Hauptaktivität:

     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; } 

    Dies ist der Teil der FrameLayout.onMeasure() Funktion, die Teil des Android API 19 Quellcodes ist, wo es abstürzt:

     @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); } } } } 

  • Berechtigung von Manifest funktioniert nicht in Android 6
  • WeakReference / AsyncTask-Muster in Android
  • Änderungs-Symbol der Navigations-Schublade
  • Bei der Verwendung von RecyclerView GridLayoutManager ist es nicht die gleiche Breite, um den Spaltenabstand durch ItemDecoration zu erstellen
  • <Uses-permission> tag erscheint nach <application> tag
  • Wie aktiviere ich SSL-Debugging auf der Android-Plattform?
  • 6 Solutions collect form web for “NullPointerException in FrameLayout.onMeasure ()”

     View customView = inflater.inflate(R.layout.custom_action_bar_tabs, null); 

    Das ist wahrscheinlich die Quelle deines Problems. Wenn du in null übergeht, weiß der Beschwörer nicht, welche Art von LayoutParams zu generieren (es erzeugt sie aus der übergeordneten ViewGroup). Ich glaubte, dass diese generierte Standard-ViewGroup.LayoutParams, aber vielleicht gibt es keine LayoutParams überhaupt.

    Sie sollten dies ersetzen mit:

     View customView = inflater.inflate(R.layout.custom_action_bar_tabs, parent, false); 

    Wo parent die ViewGroup ist, in die customView hinzugefügt wird. Wenn Sie kein verfügbares Elternteil haben, können Sie einige benutzerdefinierte LayoutParams manuell festlegen:

     View customView = inflater.inflate(R.layout.custom_action_bar_tabs, null); customView.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 

    Ausgabe 2:

    Da die Ausnahme während des Layouts angehoben wird, sehen zwei Anrufe in der validateView Methode iffy aus. Ersetzen Sie die beiden Anrufe wie mViewPager.setVisibility(View.GONE); : mViewPager.setVisibility(View.GONE); Mit mViewPager.setVisibility(View.INVISIBLE);

    Der Übergang zwischen gegangen und sichtbar, wenn der Globus-Modus eingegeben wird, löst das Layout aus. Gehen von unsichtbar zu sichtbar wird nicht auslösen Layout und das ist eine gute Vermutung, wo ein NPE passiert.

    Aktualisieren. Basierend auf deinem Kommentar, nehmen wir an, dass der gegangene -> sichtbare Übergang nur ein NPE in einem anderen Layout auslöst, dh in deiner benutzerdefinierten Aktionsleiste.

    Durch das Dumping der Ansichtshierarchie einer Beispiel-App (Eclipse> DDMS> Dump View Hierachy für View Automator) fand ich ein paar FrameLayouts in meiner FrameLayouts , was interessant ist. Meine Beispiel-App ist nicht mit Ihrer benutzerdefinierten Ansicht natürlich, aber auch im Icon / Home-Teil der Action-Bar gibt es eine ImageView in einem Frame-Layout.

    Also, versuchen Sie, diesen kniffligen Code zu ersetzen:

     // 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); 

    Mit diesem einfacheren Code, der das Gleiche auf eine sichere Weise machen sollte:

     mActionBar.setCustomView(R.layout.action_bar_icons); mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 

    Wenn das nicht der FrameLayouts deine tatsächliche Ansicht FrameLayouts und die FrameLayouts in deiner benutzerdefinierten FrameLayouts untersuchen.

    Ich habe am Ende einen Bug gegen AOSP abgelegt:

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

    Die (eher knappe) Antwort, die ich dort bekam, zeigte, dass es in der ViewPager.onMeasure() Funktion versucht, alle anstehenden Fragment auszuführen. Leider klingt es wie mein Zeigen / Verstecken der anderen Fragmente stören diesen Prozess und verursachen die NPE.

    Der Workaround, den sie ermutigten, war für mich, FragmentManager.executePendingTransactions() am Ende meiner validateView() Funktion viewPager , vermutlich um die Fragmenttransaktionen zu beenden, die ich begangen habe, damit der viewPager nicht von ihnen betroffen ist.

    Du hast falsche ID:

     <ProgressBar android:id="@+id/trover_list.loading" ... /> 

    Du kannst keinen Punkt benutzen . verkohlen.

    Nur eine Ahnung, aber versuchen, setHighlightedIconButton (); Nach dem schaltkasten in validateView (). Dies kann die NEWS_MODE-Kinder dazu zwingen, hoffentlich den Null-Zeiger in onMeasure zu verhindern, wenn Sie den Hintergrund ändern.

    Ich werde einen Stich machen. Eine Sache, die herausspringt, ist, dass das dynamische Optionsmenü auf unkonventionelle Weise umgesetzt wird. Sie sollten stattdessen verwenden:

     public boolean onCreateOptionsMenu(final Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return super.onCreateOptionsMenu(menu); } 

    Gefolgt von:

     public boolean onPrepareOptionsMenu(final Menu menu) { boolean auth = AuthManager.get().isAuthenticated(); MenuItem item = menu.findItem(R.id.menu_notifications); if (item != null) { item.setVisible(auth); } item = menu.findItem(R.id.menu_recommended_users); if (item != null) { item.setVisible(auth); } return super.onPrepareOptionsMenu(); } 

    Die beiden Änderungen sind: (1) Verwenden von onPrepareOptionsMenu für dynamische Änderungen an dem Menü und (2) sicherstellen, um durch die onPrepareOptionsMenu aufzurufen.

    Wenn ich meinen eigenen Code betrachte, sehe ich, dass ich die Regel (2) gebrochen habe, ohne ein Problem zu haben, aber wenn der Code abstürzt, ist es einen Versuch wert.

    Für Android 3+ musst du invalidateOptionsMenu() anrufen, um einen neuen Aufruf zur Vorbereitungsmethode auszulösen, aber ich sehe das schon in deinem Code so, dass es gut geht.

    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.