ListView très lent lors du défilement (à l'aide de ViewHolder/recyclage)
Mise à JOUR 2011-08-29
Si je supprime l'image dans le NodePickup, le lagginess est allé.
La question est pourquoi?
----
Je suis de retour à l'essai de certaines Android dev de nouveau. J'ai un "vieux" téléphone HTC Hero qui traînent, j'ai donc démarré que l'on fait des mises à jour et sont maintenant n cours d'exécution à nouveau avec Eclipse et le reste.
J'ai Android 2.1 en cours d'exécution sur l'appareil.
J'ai fait une épreuve très simple application qui ne marche pas à faire quoi que ce soit, sauf pour montrer certaines Activités, par exemple. Même si il n'y a pas de connexion de base de données, pas de données lues à partir de n'importe quel réseau, l'application est très lente. TRÈS lent.
Par exemple, j'ai une ListView avec quelques éléments de mise en page. Lors de l'ajout de seulement 6 à 7 éléments (de sorte que je reçois le défilement) il est incroyablement lent lors du défilement. Aussi, j'ai quelques boutons qui modifie l'Activité et aussi, c'est très très lent:
mButtonListenerUPP = new OnClickListener() {
@Override
public void onClick(View v)
{
Intent myIntent = new Intent(BaseActivity.this, ActivityMain.class);
BaseActivity.this.startActivity(myIntent);
}
};
Je ne peux pas comprendre pourquoi, donc, Im juste de poster le code ici et espère que quelqu'un a quelque astuce pour moi =)
Thx!
La Carte, NodeRowAdapter
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.view.*;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class NodeRowAdapter extends ArrayAdapter
{
private Activity context;
private ArrayList<Node> mList;
private LayoutInflater inflater;
NodeRowAdapter(Activity context, ArrayList<Node> objects)
{
super(context, R.layout.nodepickup, objects);
this.context=context;
mList = objects;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
class ViewHolder
{
TextView name;
TextView time;
TextView road;
Node node;
}
public Node getNode(int position)
{
if (mList != null && mList.size() > position)
return mList.get(position);
else
return null;
}
public View getView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
ViewHolder holder;
if (view == null)
{
view = inflater.inflate(R.layout.nodepickup, parent, false);
holder = new ViewHolder();
holder.name =(TextView)view.findViewById(R.id.name);
holder.time =(TextView)view.findViewById(R.id.time);
holder.road =(TextView)view.findViewById(R.id.road);
view.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
Node node = mList.get(position);
holder.name.setText(node.name);
holder.time.setText(node.time);
holder.road.setText(node.road);
return(view);
}
}
L'activité principale de ActivityMain
public class ActivityMain extends BaseActivity
{
private NodeRowAdapter _nodeRowAdapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SICApplication._myContext = this;
SICApplication._myContext = this;
_nodeRowAdapter = new NodeRowAdapter(this, SICApplication.dataHolder_activityMain._nodes);
ListView listView1 = (ListView) findViewById(R.id.ListViewNodes);
listView1.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Node node = _nodeRowAdapter.getNode(position);
Log.v("MyApp", "Node=" + node.name);
}
});
listView1.setAdapter(_nodeRowAdapter);
}
/* Handles item selections */
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.add_item:
addNodeItem();
return true;
}
return false;
}
private void addNodeItem()
{
_nodeRowAdapter.add(new Node("Test", "asd asd ", "14:00", 1));
}
}
La coutume élément de la liste, NodePickup
public class NodePickup extends LinearLayout
{
public NodePickup(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.nodepickup, this);
this.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMessage("Ajabaja!")
.setCancelable(true)
.setPositiveButton("JA!", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
dialog.cancel();
}
});
builder.show();
}
});
}
}
Et enfin, la NodePickup XML de mise en page
<LinearLayout
android:id="@+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="64dip"
android:orientation="horizontal"
android:background="@drawable/stateful_background"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="@+id/ImageView01"
android:layout_width="40dip"
android:layout_height="40dip"
android:src="@drawable/arrow_up_green"
android:background="@android:color/transparent">
</ImageView>
<LinearLayout
android:id="@+id/LinearLayout02"
android:background="@android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:text="14:46 (15 min)"
android:id="@+id/time"
android:textSize="12dip"
android:textColor = "#000000"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent">
</TextView>
<TextView
android:text="test"
android:id="@+id/road"
android:textSize="12dip"
android:textColor = "#000000"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent">
</TextView>
<TextView
android:text="test test"
android:id="@+id/name"
android:textSize="12dip"
android:textColor = "#000000"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent">
</TextView>
</LinearLayout>
</LinearLayout>
Thx, j'ai essayé. Na pas me dire quoi que ce soit. Peut-être que je suis absent de somethuing. Cependant, il semble que c'est l'ImageView qui le fait. Si je supprime que de NodePickup, sa rapidité de nouveau
OriginalL'auteur Ted | 2011-08-28
Vous devez vous connecter pour publier un commentaire.
Le point de vue a un moment difficile de déterminer comment la mise en page doit être rendu. Le xml que vous avez posté ne l'aide pas beaucoup. Si vous retirez de l'ImageView puis le LinearLayout02 prendra toute la largeur de la société mère. Mais avoir l'imageView avec standar dimentions et la mise en page à droite fill_parent confond le mal. Les demandes de la taille de l'imageView de nouveau à "pousser les marges à droite" (genre de). Jetez un oeil à mes suggestions ci-dessous
Tip1
utiliser le LinearLayout bien le poids. Faire de l'imageView fill_parent et le LinearLayout trop (pour la largeur) et de jouer avec le poids propriétés.
Le faire également pour la mise en page verticale avec le TextViews. La meilleure Solution devrait être de mettre une taille fixe à la hauteur de la TextViews la pensée.
Également envisager de modifier la vue de dessus à RelativeLayout. Faire de l'image avec la norme dimentions , AlignParentLeft et de mettre le LinearLayout02 toRightOf imageView. Vous allez à l'allégement de la onMeasure de la ViewGroup beaucoup.
Tip2
Il semble que lorsque les modifications du texte de la hauteur de la vue doivent être reinflated.Une commune de la technique pour éviter que ça à faire Élément de la liste fixée en hauteur. Si la liste peut réutilisation, le recyclage vues sans avoir à les renflouer.
Tip3
Donner votre LinearLayout02 une hauteur fixe de 64dp ou Fill_Parent puisque vous n'avez pas toute la gauche de l'espace, mais la Mise en page ne sais pas qui et essayer de réorganiser elle-même à chaque fois, puisque le texte est également Wrap_content.
Également vous dit que si vous retirez de l'ImageView tout est plus rapide encore.Si le ci-dessus ne sont pas pouvez-vous s'il vous plaît essayer ce? Puisque vous savez que imageView taille est fixe.
Prolonger votre imageView et remplacer requestLayout() la méthode.
Maintenant inclure le MyImageView widget à votre XML comme ça.
C'est incroyable hwo lisse ma ListView défile depuis que je suis avec vous "Astuce 3". Comment avez-vous trouvé cela? / Pourriez-vous expliquer POURQUOI il en est ainsi ou si il y a des inconvénients?
le point de vue qui sait que sa dimension n'essayez pas de les comprendre. avec wrap_content il est en train de le faire au moment de l'exécution.
astuce 3 fixe, 80% de mon retard.
OriginalL'auteur weakwire
Après l'optimisation de mon getView() la méthode à utiliser un support et à la réutilisation convertView si ce n'est pas null, mon listview était encore assez de lag.
Ensuite, j'ai essayé
et résolu à la fois.
Espère que cela aide quelqu'un.
Je l'ai vu plusieurs fois en tapant des suggestions. Mais ils ne connurent jamais le but. +1
OriginalL'auteur yunusual
Je viens de découvrir ce sujet et je veux partager avec vous les gars.
J'ai essayé TOUTES les solutions proposées mais rien n'a fonctionné. Quelle était la cause du problème est la longueur du texte, je suis d'alimentation de l'un de mes TextView points de vue parce que je suis en utilisant
dans ma carte dans ma méthode getView. Maintenant que j'ai diminué ma Chaîne, la liste est TRÈS lisse 🙂
OriginalL'auteur AlAsiri
Il a fallu un certain temps! J'ai tout essayé. Désactiver le défilement cache, viewHolder, cacheColorHint ... mais rien n'a fonctionné!
Après avoir cherché de nombreuses heures, j'ai trouvé la racine de tous les maux!
Dans mon themes.xml j'ai eu une mise à l'échelle de l'image de fond:
Après la suppression de la beackground tout était du beurre lisse.
J'espère que cela aide quelqu'un!
OriginalL'auteur Felix
Pour améliorer les performances de listview utiliser les deux ou l'un des deux (Simple mise en œuvre)
Si vous avez modérément longues listes je recommande ViewHolder sinon pour les grandes listes (comme dans le cas d'un lecteur de musique), je recommande d'utiliser ViewHolder avec AsyncTask. La clé de la lisse ListView défilement est de réduire la consommation de mémoire autant que possible.
À mettre en œuvre ViewHolder, est simple. Il suffit de créer une classe statique dans votre Adaptateur personnalisé qui contient toutes les vues que vous trouverez via findViewById. Donc, c'est comment il devrait ressembler -
Alors, la prochaine fois vous avez besoin de findViewById ces points de vue, juste référence à la ViewHolder comme celui-
C'est code testé et pris de l'un de mes projets. Toutefois, la source d'origine est ici - http://developer.android.com/training/improving-layouts/smooth-scrolling.html
Les listes deviennent plus à l'aide de ViewHolder. À l'aide de AsyncTask est un peu plus complexe, mais ne consultez le lien si vous souhaitez mettre en place la AsyncTask avec ViewHolder pour un beaucoup plus lisse de défilement de l'expérience. Bonne Chance!
OriginalL'auteur Advait S
La charge de l'image une fois en tant que Bitmap et de l'appliquer à l'ImageView par programme après avoir gonflé. Si vous avez besoin de différentes images par article, vous devez créer les images de manière asynchrone comme décrit dans Android: Comment optimiser le ListView avec ImageView + 3 TextViews?
J'ai différentes images à afficher, en fonction de l'état de mon objet. Mais pour les récupérer "asynch" semble totalement inutile. Ils sont fournis avec l'application, pas besoin de les télécharger...
Même si les images sont locaux, ils pourraient avoir besoin d'un certain temps à charger, par exemple, lorsque vous souhaitez afficher les photos des contacts: ils peuvent être très grandes et ont besoin d'être revus à la baisse. Dans un ListView cela conduirait à de notable de retard. Emballés, les images devraient probablement être bon, sauf si vous avez un dispositif très lent.
OriginalL'auteur mattlaabs
Essayez d'utiliser
android:cacheColorHint="#00000000"
pour votre liste. Pour améliorer les performances d'affichage pendant le défilement des opérations, l'Android cadre réutilise le cache de couleur indice.Référence: developer.android.com article.
l'extra 00 signifie que le canal alpha, donc ça va être transparent
pour l'utiliser il n'y a pas de changement dans la performance. encore listview défilement lent.
OriginalL'auteur Ronnie
Cela Peut aider quelqu'un
Si vous avez une image de votre Élément de la liste, vous devez vous rappeler de réduire la qualité de l'Image. C'est attribuer plus rapide à charger dans quelques Ko que quelques mégaoctets.
Cela m'a aidé
OriginalL'auteur Ruan
J'ai eu le même problème avant, alors que j'étais à l'aide de différents layout comme LinearLayout, RelativeLayout, CardView en tant que parent d'enfant différent dans la même liste d'éléments. J'ai résolu le problème en changeant tous vue à l'intérieur de RelativeLayout.
À l'aide de RelativeLayout comme principal et il est enfant de mise en page peut augmenter la vitesse de chargement de chaque élément. Donc, le défilement se fera en douceur.
OriginalL'auteur Vinil Chandran
Vous pouvez utiliser
listview.setScrollingCacheEnabled(false).Lorsque le défilement listview application maintenez alors la zone de jeter De la Mémoire(OOM) exception à la règle.Ma solution est travaillé pour moi.
OriginalL'auteur Fatih Kocaman