web-dev-qa-db-fra.com

NullPointerException avec les feuilles de fond AppCompat

LinearLayout bottomSheetViewgroup = (LinearLayout) findViewById(R.id.bottomSheet);

bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetViewgroup);

bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); //this line

J'ai ce code dans la méthode onCreate () de mon activité et j'obtiens l'exception NPE ci-dessous lorsque la dernière ligne est exécutée:

Causée par: Java.lang.NullPointerException: Tentative d'invoquer la méthode virtuelle 'Java.lang.Object Java.lang.ref.WeakReference.get ()' sur un objet de référence null Sur Android. support.design.widget.BottomSheetBehavior.setState (BottomSheetBehavior.Java:440)

14
Sanf0rd

Bien que la réponse de Sanf0rds soit correcte, elle ne permet pas de définir la feuille inférieure comme étant développée par défaut. Le problème est dû au fait que WeakReference n'est pas défini jusqu'à la dernière ligne de onLayoutChild.

La solution consiste à fournir notre propre classe qui étend BottomSheetBehavior, mais en définissant l'état dans un onLayoutChild surchargé. Le code est fourni ci-dessous.

uk/ac/qub/quibe/misc/ExpandedBottomSheetBehavior.Java

package uk.ac.qub.quibe.misc;

import Android.content.Context;
import Android.support.design.widget.CoordinatorLayout;
import Android.util.AttributeSet;
import Android.view.View;

/**
 * Created by mcp on 15/03/16.
 */
public class ExpandedBottomSheetBehavior<V extends View> extends Android.support.design.widget.BottomSheetBehavior<V> {

    public ExpandedBottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onLayoutChild(final CoordinatorLayout parent, final V child, final int layoutDirection) {
        SavedState dummySavedState = new SavedState(super.onSaveInstanceState(parent, child), STATE_EXPANDED);
        super.onRestoreInstanceState(parent, child, dummySavedState);
        return super.onLayoutChild(parent, child, layoutDirection);
        /*
            Unfortunately its not good enough to just call setState(STATE_EXPANDED); after super.onLayoutChild
            The reason is that an animation plays after calling setState. This can cause some graphical issues with other layouts
            Instead we need to use setInternalState, however this is a private method.
            The trick is to utilise onRestoreInstance to call setInternalState immediately and indirectly
         */
    }

}

Dans la référence de fichier de mise en page, faites référence à votre nouveau comportement personnalisé.

Changement

app:layout_behavior="Android.support.design.widget.BottomSheetBehavior"

À

app:layout_behavior="uk.ac.qub.quibe.misc.ExpandedBottomSheetBehavior"
14
McP
public class ExpandedBottomSheetBehavior<V extends View> extends
    Android.support.design.widget.BottomSheetBehavior<V> {

  public ExpandedBottomSheetBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);
}

  @Override
  public boolean onLayoutChild(final CoordinatorLayout parent, final V child, final int layoutDirection) {
    return super.onLayoutChild(parent, child, layoutDirection);
  }

  @Override
  public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
    try {
      return super.onInterceptTouchEvent(parent, child, event);
    } catch (NullPointerException ignored) {
      return false;
    }
  }
}
4
Rainita Gurjar

Le problème avec votre code est que vous essayez d'appeler la méthode setState directement dans onCreate. Ceci lancera un nullPointer car le WeakReference n'est pas encore initialisé. Il sera initialisé lorsque la mise en page du coordinateur est sur le point de poser sa vue enfant.

onLayoutChild (parent CoordinatorLayout, enfant V, int layoutDirection)

Appelé lorsque le parent CoordinatorLayout concerne la présentation de la vue Donnée.

La meilleure approche consiste donc à définir la hauteur de coup d'oeil sur 0 et d'afficher/masquer l'intérieur de l'écouteur onItemClick. 

J'ai répondu à cette question ici: https://stackoverflow.com/a/36236743/1314796

2
Rohit Ramkumar

J'ai trouvé une solution mais je ne sais toujours pas pourquoi cela se produit. La solution est mise sur cette dernière ligne pour appeler l'utilisateur directement après que l'activité soit en cours. Ex: dans un rappel contextMenu ou dans n’importe quel OnClickListener.

1
Sanf0rd

Vous pouvez également envisager d'écouter l'événement de mise en page global. Ainsi, vous serez sûr que la feuille de fond a été mise en page lors de la définition de l'état réduit. 

final View bottomSheet = findViewById(R.id.bottom_sheet);
bottomSheet.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            bottomSheet.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
            bottomSheetBehavior.setPeekHeight(300);
            bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    });
1
LeonLu