Pourquoi les poids imbriqués sont-ils mauvais pour les performances? Des alternatives?

160

J'ai écrit quelques fichiers de mise en page dans lesquels j'ai utilisé l' layout_weightattribut pour créer un rapport entre différentes vues.

À un moment donné, je commence à recevoir des avertissements de peluches concernant les poids imbriqués.

Donc, je me demande pourquoi les poids imbriqués sont mauvais pour les performances, et s'il existe un moyen plus efficace de créer un rapport constant entre les dimensions de vue qui pourrait être utilisé pour différentes tailles d'écran et qui n'a pas besoin de spécifier beaucoup de valeurs de dpi de dimension à travers plusieurs fichiers de mise en page (pour différentes tailles d'écran, je veux dire).

Je vous remercie!

MobileCushion
la source
2
Un article génial pour le développeur d'
Muhammad Babar

Réponses:

140

Les pondérations imbriquées sont mauvaises pour les performances car:

Les poids de mise en page nécessitent qu'un widget soit mesuré deux fois. Lorsqu'un LinearLayout avec des poids différents de zéro est imbriqué dans un autre LinearLayout avec des poids différents de zéro, le nombre de mesures augmente de façon exponentielle.

Il est préférable d'utiliser RelativeLayout et d'ajuster votre vue en fonction des emplacements des autres vues sans utiliser de valeurs dpi spécifiques.

CD
la source
87
Bonne chose à savoir, ce qui, je suppose, est le but du message. Je voudrais souligner que l'impact exponentiel est encore minuscule si l'exposant en cause est faible. Pour les petites profondeurs de nidification, ne pas utiliser le processeur requis pour ce faire, c'est comme avoir un cheval de bataille que vous chouchoutez toute la semaine et que vous ne faites marcher que le dimanche. Pourtant, pour de grandes profondeurs de nidification, c'est un point bien pris.
Carl
14
RelativeLayout a également besoin de mesurer deux fois pour s'assurer que la disposition de tous ses enfants est correcte, donc changer LinearLayout avec poids de disposition en RelativeLayout peut ne pas améliorer les performances.
Piasy
La mise en page relative ne fonctionne pas toujours. Dans les cas où vous devez construire des widgets proportionnels
Abdurakhmon
67

Mise à jour: comme nous le savons, la bibliothèque de support pour cent est obsolète à partir du niveau 26 de l'API. ConstraintLayoutC'est la nouvelle façon d'obtenir la même structure XML plate.

Projet Github mis à jour

Échantillons mis à jour:

<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/fifty_thirty"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ffff8800"
        android:gravity="center"
        android:text="@string/fifty_fifty_text"
        android:textColor="@android:color/white"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.5"
        android:textSize="25sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.5" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ffff5566"
        android:gravity="center"
        android:text="@string/fifty_fifty_text"
        android:textColor="@android:color/white"
        android:textSize="25sp"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.5"
        app:layout_constraintLeft_toRightOf="@id/fifty_thirty"
        app:layout_constraintTop_toBottomOf="@id/fifty_thirty"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.5" />

</android.support.constraint.ConstraintLayout>

Mise à jour: Une excellente nouvelle bibliothèque de support pour pourcentage Android résout notre problème de performances et de pondération imbriquée désordonnéeLinearLayout

compile 'com.android.support:percent:23.0.0'

Démo ICI

Considérez cette mise en page simple pour démontrer la même chose.

percent support démo de libray

<android.support.percent.PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/fifty_huntv"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff7acfff"
        android:text="20% - 50%"
        android:textColor="@android:color/white"
        app:layout_heightPercent="20%"
        app:layout_widthPercent="50%" />
    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_toRightOf="@id/fifty_huntv"
        android:background="#ffff5566"
        android:text="80%-50%"
        app:layout_heightPercent="80%"
        app:layout_widthPercent="50%"
        />

</android.support.percent.PercentRelativeLayout>

Dégrader de performance évité imbriqué LinearLayoutavec des poids. Vraiment génial !!!.

nitesh
la source
@dan Oui, étant donné que nous avons une disposition linéaire imbriquée avec des poids.
nitesh
3
"Cette classe est obsolète au niveau d'API 26.0.0-beta1. Pensez à utiliser ConstraintLayout et les mises en page associées à la place." developer.android.com/reference/android/support/percent/…
saiyancoder
7
Je n'aime pas ConstraintLayout. Cela ne se comporte pas intuitivement pour moi
Carson Holzheimer
8
le ConstraintLayout est si difficile pour moi
BertKing
1
peut-être que les explications données par apple sur les contraintes de mise en page automatique sont plus claires, et comme la logique est la même, cela peut aider. Malheureusement, je trouve que ConstraintLayout de droïde est plus lourd / détaillé à utiliser que AutoLayout d'iOS
AdricoM
46

Je pense (et je serai probablement flambé pour cela), mais encore une fois, je pense que mon téléphone a un processeur quad core pour rivaliser (sinon complètement détruire) la plupart des ordinateurs personnels.

Je pense également que ce type de capacité matérielle est l'avenir des téléphones.

J'arrive donc à la conclusion, que tant que vous ne vous laissez pas emporter par l'imbrication (dans MHO, une mise en page ne devrait jamais avoir plus de 4 niveaux de profondeur, et si c'est probablement vous le faites mal), votre téléphone s'en fiche. d'avoir des poids.

Il y a beaucoup de choses que vous pouvez faire qui auront un effet beaucoup plus profond sur les performances, puis vous inquiéter que votre processeur fasse des calculs supplémentaires.

(veuillez noter que je suis légèrement humoristique, et que je ne prends donc rien de trop au sérieux dans ce post, à part l'idée qu'il y a d'autres choses que vous devez d'abord optimiser, et que vous soucier d'un poids profond de 2-3 niveaux n'aide pas votre santé)

WIllJBD
la source
2
prises, et essentiellement d'accord, mais j'ai entendu dire que l'iPhone utilise en moyenne (y compris les services / sites Web qui prennent en charge son utilisation) à peu près la même quantité d'énergie par an que le réfrigérateur domestique moyen des États-Unis. Il est donc de notre responsabilité en tant que développeur de prendre en compte ce type d'impact environnemental. De toute évidence, c'est toujours un exercice d'équilibre: temps, coûts, performances, stabilité, et en général, je suis d'accord avec votre point de vue - mais pensez simplement que nous devrions également envisager ce type d'impact. De toute évidence, la maintenance / extensibilité intervient ici également. Quoi qu'il en soit - point fait et merci.
MemeDeveloper
Réalisez que le point spécifique en question concerne le traitement sur l'appareil et non sur le Web, mais signifie mon commentaire comme un point général sur les priorités en tant que développeurs plus que sur les spécificités de l'OP.
MemeDeveloper
11

La raison principale pour laquelle les poids imbriqués sont mauvais est que lorsqu'un modèle a des enfants avec un poids, il doit être mesuré deux fois (je pense que cela est mentionné dans l'avertissement de peluche). Cela signifie qu'une mise en page pondérée qui contient également une mise en page pondérée doit être mesurée quatre fois, et chaque «couche» de poids que vous ajoutez augmente les mesures avec une puissance de deux.

Dans ICS (niveau d'API 14), a GridLayoutété ajouté, ce qui permet des solutions simples et `` plates '' pour de nombreuses mises en page qui nécessitaient auparavant des pondérations. Si vous développez pour des versions antérieures d'Android, vous aurez un peu plus de mal à supprimer les poids, mais en utilisant RelativeLayoutet en aplatissant autant que possible votre disposition dans cette cabine, vous supprimez généralement une grande partie des poids imbriqués.

Jave
la source
9
Je ne pense pas que vous puissiez obtenir les mêmes résultats avec GridLayout ou RelativeLayout . Par exemple pour GridLayout: "GridLayout ne prend pas en charge le principe de poids, tel que défini en poids. En général, il n'est donc pas possible de configurer un GridLayout pour répartir l'espace excédentaire entre plusieurs composants."
Timmmm
À partir de l'API 21, la notion de poids a été ajoutée à GridLayout. Pour prendre en charge les appareils Android plus anciens, vous pouvez utiliser le GridLayout de la bibliothèque de support v7. android.support.v7.widget.GridLayout
Эвансгелист Evansgelist
2

Il existe une solution simple pour éviter les LinearLayouts imbriqués avec des poids - utilisez simplement Tablelayout avec weightSum et LinearLayout imbriqué avec weightSum - Tablelayout a les mêmes attributs que LinearLayout (orientation, weightSum, layout_weight, etc.) et n'affiche pas le message - "poids imbriqués mauvais pour les performances "

Exemple:

 <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:weightSum="1">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.8"/>


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.2"
            android:orientation="horizontal"
            android:weightSum="1">


            <ImageView
                android:layout_height="match_parent"
                android:layout_width="0dp"
                android:layout_weight="0.4"/>

            <TextView
                android:layout_height="match_parent"
                android:layout_width="0dp"
                android:layout_weight="0.6"/>


            </LinearLayout>

    </TableLayout>
Eneyovich
la source
1

Je pense que la seule alternative est de créer une fonction qui s'appellerait onResume et qui définira toutes les tailles et positions. Quoi qu'il en soit, en poids, vous ne pouvez définir que des tailles, mais pas de remplissage (les mises en page deviennent encore plus compliquées), pas de textSize (impossible de compenser cela d'une manière ou d'une autre), et encore moins de choses telles que le nombre de lignes.

Gangnus
la source