Koxx Posté(e) 16 juillet 2010 Share Posté(e) 16 juillet 2010 Bonjour a tous, j'ai un soucis avec l'implémentation des listviews dans les Launcher ADW, Launcher Pro et Launcher+. L'ensemble du code est visible ici: http://code.google.com/p/android-launcher-plus/source/browse/ mais ce qui m'interesse plus particulierement est le BaseAdapter de la listView: http://code.google.com/p/android-launcher-plus/source/browse/trunk/src/mobi/intuitit/android/widget/WidgetListAdapter.java A chaque getView, je vois le memoire qui baisse ... qui baisse. Jusqu'a ce que le garbage collector decide a passer (environ a 1Mb de libre)... Ca ne me parait pas tres sain et je ne comprend pas trop pourquoi. Je me pose la question de decoder toutes les images a l'exterieur du getView, mais ca me parait assez dangereux en terme d'utilisation memoire. Ce qui me semble vraiment étrange, c'est que la mémoire ne soit libérée que par le GC. Aucun autre moyen de réutiliser les views ? Comment puis-je améliorer ce code ? Ce code est tout frais, j'ai tout cassé par rapport a l'implémentation des widgets scrollables pour ne plus lier le Launcher par un cursor en permanence à l'appli (ce qui crashait le Launcher quand le widget crashait). Lien vers le commentaire Partager sur d’autres sites More sharing options...
dekans Posté(e) 16 juillet 2010 Share Posté(e) 16 juillet 2010 Je suis pas sûr d'être pertinent dans ce que j'avance mais c'est pas le principe du viewholder de régler ce problème ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
acesyde Posté(e) 16 juillet 2010 Share Posté(e) 16 juillet 2010 Comme le dit Dekans normalement si tu utilises un viewholder (tu dois le faire en faite) ta mémoire ne se vois pas ré-allouée mais réutilisé et donc normalement tu ne devrais pas avoir de soucis. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Koxx Posté(e) 16 juillet 2010 Auteur Share Posté(e) 16 juillet 2010 En fait, je vois pas trop le principe du pattern viewHolder... et surout comment l'appliquer dans ce cas particulier ou tous mes View sont tres variables. Dans mon cas, je n' 'inflate' pas la vue a chaque fois... et je reutilise bien le 'convertView' a chaque fois. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Koxx Posté(e) 16 juillet 2010 Auteur Share Posté(e) 16 juillet 2010 Pour moi, le viewHolder sert uniquement a stocker les identifiants des ressources pour eviter les 'findViewById' a chaque getView... ca m'étonnerai que ce soit ca qui permettent de gagner de la memoire. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Nivek Posté(e) 16 juillet 2010 Share Posté(e) 16 juillet 2010 Après un très rapide (étant donné la complexité du code pour gérer les différents types) coup d'oeil : - Les Adapters sont équipés pour pouvoir gérer des Types d'items différents et te fournir dans le convertview du getView() une vue exactement du type dont tu es sensé avoir besoin pour l'item qu'il solicite. Pour utiliser ce mécanisme il faut surcharger : http://d.android.com/reference/android/widget/Adapter.html#getViewTypeCount() pour renvoyer le nombre total de types d'items potentiels dans ta liste (ce nombre ne doit pas varier dans le temps) http://d.android.com/reference/android/widget/Adapter.html#getItemViewType(int) pour fournir Type d'item pour un id donné. En gros, avant de faire un getView(), la liste fait d'abord un appel à getItemViewType() pour savoir de quel type d'item il s'agit, regarde dans son pool de views si elle en a un prêt à être recyclé, et te le fournis dans getView() via convertView. Par rapport à ton Adapter, je ne sais pas avec ce premier coup d'oeil si il est possible d'utiliser ce principe... tout ce que j'ai vu c'est que tu manipules des types de vues sans surcharger ces méthodes, donc c'est pour moi une piste possible. Second point, la manipulation des Bitmap sous Android.......... Là ça devient chaud... quand on manipule un grand nombre de bitmaps sous android, on arrive souvent à des saturations mémoire. On cherche un peu et on se rend compte qu'il existe un .recycle() miraculeux... que les devs android (Romain Guy en premier plan) considèrent comme n'ayant pas à être appelés par les développeurs d'applis. On finit tout de même par en mettre par ci par là, et c'est plutôt efficace... jusqu'à ce qu'on retrouve avec des problèmes d'utilisation de bitmaps déjà recyclées, et là on pleure. Pour ma part, en développant EmailAlbum au fur et à mesure, j'ai fini par aboutir à la mise en place d'une surcouche pour faire l'intermédiaire entre mes activity et BitmapFactory. Cette surcouche se trouve ici : http://code.google.com/p/emailalbum/source/browse/EmailAlbumAndroid/trunk/src/com/kg/emailalbum/mobile/util/BitmapLoader.java En gros, les fonctionnalités de cette classe : - chargement des bitmaps en deux temps pour ne charger en mémoire que le strict minimum par rapport à la résolution cible demandée - gestion d'un LRUCache des bitmaps : si une image a déjà été chargée en mémoire (en fonction de son uri), on ne la recharge pas à moins qu'on ait besoin d'une résolution plus élevée. Ce cache se vide de ses éléments les plus anciens quand la mémoire vient à manquer (utilisation de SoftReferences). Voilà les premières pistes que je peux te donner vu que je n'ai pas le temps d'aller plus loin pour le moment. Tu peux toujours fouiller dans le code d'EmailAlbum, je gère des listes contenant des bitmaps dans : http://code.google.com/p/emailalbum/source/browse/EmailAlbumAndroid/tags/REL-2_8_0/src/com/kg/emailalbum/mobile/creator/EmailAlbumEditor.java : liste ordonnancable de vignettes légendables http://code.google.com/p/emailalbum/source/browse/EmailAlbumAndroid/tags/REL-2_8_0/src/com/kg/emailalbum/mobile/creator/SelectPictures.java : gridview des images de la gallerie http://code.google.com/p/emailalbum/source/browse/EmailAlbumAndroid/tags/REL-2_8_0/src/com/kg/emailalbum/mobile/viewer/EmailAlbumViewer.java : liste d'images contenues dans une archive Lien vers le commentaire Partager sur d’autres sites More sharing options...
Nivek Posté(e) 16 juillet 2010 Share Posté(e) 16 juillet 2010 Oui le viewHolder permet de gagner en fluidité de scrolling, pas en mémoire. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Koxx Posté(e) 16 juillet 2010 Auteur Share Posté(e) 16 juillet 2010 merci Nivek pour ces infos ! Pour le point 1, j'ai pas bien compris, mais je vais creuser. Pour le point 2, c'est exactement ceux a quoi je pensais... donc, je vais certainement essayer ca. Reste que même sans les bitmaps, ca mange la mémoire au fur et a mesure du scrolling. Exemple ici avec juste du texte, ca mange 500Ko avec juste quelques aller retour de scrolling : http://pastebin.com/tCQpjmXg Pour le ViewHolder, je suis en train de tester ca ;) Lien vers le commentaire Partager sur d’autres sites More sharing options...
Koxx Posté(e) 16 juillet 2010 Auteur Share Posté(e) 16 juillet 2010 Je viens d'ajouter les choses suivantes : - un viewHolder permettant de s'affranchir des findViewById - un limiteur de nombre de view max http://code.google.com/p/android-launcher-plus/source/browse/trunk/src/mobi/intuitit/android/widget/WidgetListAdapter.java Qu'en pensez-vous ? Ca ne m'a pas l'air de changer grand chose au niveau memoire, mais effectivement, ca a l'air un poil plus rapide. A part, le decodage/stockage/reutilisation des bitmaps a ajouter, tu vois mieux a faire ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
Koxx Posté(e) 16 juillet 2010 Auteur Share Posté(e) 16 juillet 2010 et chiote !! Je me disais, cool, ca a l'air stable. Je lance le browser, je reviens a la Home ... et crash ! http://pastebin.com/5NMRpCvz # # 07-16 13:54:19.155: DEBUG/LauncherPP_WLA(13357): freeMemory = 2527 Kb # 07-16 13:54:19.155: ERROR/dalvikvm-heap(13357): 58512-byte external allocation too large for this process. # 07-16 13:54:19.155: ERROR/(13357): VM won't let us allocate 58512 bytes # 07-16 13:54:19.155: DEBUG/skia(13357): --- decoder->decode returned false # 07-16 13:54:19.163: DEBUG/LauncherPP_WLA(13357): ****** freeMemory = 2492 Kb # 07-16 13:54:19.163: WARN/System.err(13357): java.lang.OutOfMemoryError: bitmap size exceeds VM budget # 07-16 13:54:19.233: WARN/System.err(13357): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) # 07-16 13:54:19.233: WARN/System.err(13357): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459) # 07-16 13:54:19.233: WARN/System.err(13357): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:271) # 07-16 13:54:19.241: WARN/System.err(13357): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:296) # 07-16 13:54:19.241: WARN/System.err(13357): at android.graphics.drawable.Drawable.createFromPath(Drawable.java:801) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.ImageView.resolveUri(ImageView.java:501) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.ImageView.setImageURI(ImageView.java:289) # 07-16 13:54:19.241: WARN/System.err(13357): at mobi.intuitit.android.widget.WidgetListAdapter.bindView(WidgetListAdapter.java:380) # 07-16 13:54:19.241: WARN/System.err(13357): at mobi.intuitit.android.widget.WidgetListAdapter.getView(WidgetListAdapter.java:505) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.AbsListView.obtainView(AbsListView.java:1256) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.ListView.makeAndAddView(ListView.java:1668) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.ListView.fillDown(ListView.java:637) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.ListView.fillGap(ListView.java:608) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:2531) # 07-16 13:54:19.241: WARN/System.err(13357): at android.widget.AbsListView.onTouchEvent(AbsListView.java:2001) # 07-16 13:54:19.249: WARN/System.err(13357): at android.widget.ListView.onTouchEvent(ListView.java:3234) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.View.dispatchTouchEvent(View.java:3709) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:851) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:883) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:883) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:883) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:883) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:883) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:883) # 07-16 13:54:19.249: WARN/System.err(13357): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:883) # 07-16 13:54:19.249: WARN/System.err(13357): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659) # 07-16 13:54:19.249: WARN/System.err(13357): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107) # 07-16 13:54:19.257: WARN/System.err(13357): at android.app.Activity.dispatchTouchEvent(Activity.java:2061) # 07-16 13:54:19.257: WARN/System.err(13357): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643) # 07-16 13:54:19.257: WARN/System.err(13357): at android.view.ViewRoot.handleMessage(ViewRoot.java:1691) # 07-16 13:54:19.257: WARN/System.err(13357): at android.os.Handler.dispatchMessage(Handler.java:99) # 07-16 13:54:19.257: WARN/System.err(13357): at android.os.Looper.loop(Looper.java:123) # 07-16 13:54:19.257: WARN/System.err(13357): at android.app.ActivityThread.main(ActivityThread.java:4363) # 07-16 13:54:19.257: WARN/System.err(13357): at java.lang.reflect.Method.invokeNative(Native Method) # 07-16 13:54:19.257: WARN/System.err(13357): at java.lang.reflect.Method.invoke(Method.java:521) # 07-16 13:54:19.257: WARN/System.err(13357): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) # 07-16 13:54:19.257: WARN/System.err(13357): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) # 07-16 13:54:19.257: WARN/System.err(13357): at dalvik.system.NativeStart.main(Native Method) # 07-16 13:54:19.264: DEBUG/LauncherPP_WLA(13357): freeMemory = 2454 Kb Lien vers le commentaire Partager sur d’autres sites More sharing options...
Nivek Posté(e) 19 juillet 2010 Share Posté(e) 19 juillet 2010 Alors, du neuf ? Je viens de me rendre compte que pour mon BitmapLoader, j'avais mis un lien vers une vieille version qui utilise un vieux cache qui fonctionne moyennement bien... celui que j'ai sur mon trunk en cours de dev fait lui usage des SoftReferences et m'a l'air bien plus efficace (mais n'est pas encore "en production") : http://code.google.com/p/emailalbum/source/browse/EmailAlbumAndroid/trunk/src/com/kg/emailalbum/mobile/util/BitmapLoader.java EDIT: et puis il y a une complexité pas utile pour toi dans cette classe : elle gère également la récupération d'images dans des archives (zip), ce qui était la fonction première de mon appli. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Koxx Posté(e) 19 juillet 2010 Auteur Share Posté(e) 19 juillet 2010 merci Nivek, j'ai réutilisé des bouts de ton code et des SoftReference trouvés sur le net, et ca a l'air beaucoup mieux. Le code scrollable dans Launcher+ a l'air parfaitement stable. Par contre, dans ADW, ca arrive encore a faire exploser le heap de temps en temps car il semble deja utiliser beaucoup de mémoire. Les explosions ne se produisent plus dans mon code car les décodages d'images sont beaucoup plus rares maintenant, mais d'autres parties du code d'ADW... Et puis, il faut dire que je vois quelques malades parmis mes utilisateurs: 7 panels de Home avec 15 widgets !!! Lien vers le commentaire Partager sur d’autres sites More sharing options...
Recommended Posts
Archivé
Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.