Cuillère Posté(e) 25 août 2010 Share Posté(e) 25 août 2010 Bonjour à tous. J'expose mon problème : J'ai une listView customs (image + texte). Je l'affiche, la scroll dans tous les sens, et après quelques temps, F/C. le logCat : 08-25 15:12:34.329: ERROR/AndroidRuntime(352): FATAL EXCEPTION: main 08-25 15:12:34.329: ERROR/AndroidRuntime(352): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.chlorophyll.passage/com.android.chlorophyll.passage.MenuEcran}: java.lang.NullPointerException 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.app.ActivityThread.access$2300(ActivityThread.java:125) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.os.Handler.dispatchMessage(Handler.java:99) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.os.Looper.loop(Looper.java:123) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.app.ActivityThread.main(ActivityThread.java:4627) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at java.lang.reflect.Method.invokeNative(Native Method) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at java.lang.reflect.Method.invoke(Method.java:521) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at dalvik.system.NativeStart.main(Native Method) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): Caused by: java.lang.NullPointerException 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at com.android.chlorophyll.passage.MenuEcran.remplirTextView(MenuEcran.java:229) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at com.android.chlorophyll.passage.MenuEcran.onCreate(MenuEcran.java:51) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627) 08-25 15:12:34.329: ERROR/AndroidRuntime(352): ... 11 more avec plusieurs fois 08-25 15:12:32.959: ERROR/dalvikvm-heap(304): 345600-byte external allocation too large for this process. 08-25 15:12:32.959: ERROR/GraphicsJNI(304): VM won't let us allocate 345600 bytes juste au dessus du premier bout du log. Je ne sais pas d'où cela peut venir, je n'ai jamais eu de problème de ce type. Si quelqu'un avait une idée. Merci à vous ! Un problème dû à la mémoire et des images trop volumineuses ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
popolbx Posté(e) 25 août 2010 Share Posté(e) 25 août 2010 Caused by: java.lang.NullPointerException 08-25 15:12:34.329: ERROR/AndroidRuntime(352): at com.android.chlorophyll.passage.MenuEcran.remplirTextView(MenuEcran.java:229) ligne 229 un pointeur nul. le probleme en plus est dans le oncreate donc rien à voir avec le scroll. ou alors ton adapter de listview est codé avec les pieds et explose la mémoire. fais voir le code du getView de ta listView (et regarde la ligne 229 histoire de voir de quel pointeur il sagit) Lien vers le commentaire Partager sur d’autres sites More sharing options...
Cuillère Posté(e) 26 août 2010 Auteur Share Posté(e) 26 août 2010 Le code du getView : @Override public View getView(int position, View convertView, ViewGroup parent){ LinearLayout newsView; Video item = getItem(position); String title = item.getTitle(); String imgUrl = item.getImageUrl(); if (convertView == null){ newsView = new LinearLayout(getContext()); String inflater = Context.LAYOUT_INFLATER_SERVICE; LayoutInflater vi; vi = (LayoutInflater)getContext().getSystemService(inflater); vi.inflate(resource, newsView, true); } else { newsView = (LinearLayout) convertView; } TextView txtTitle = (TextView)newsView.findViewById(R.id.txtTitleItemSummaryVideo); txtTitle.setText(title); imgView = (ImageView)newsView.findViewById(R.id.imgViewItemSummaryVideo); DownloadImageTask task = new DownloadImageTask(imgView); task.execute(imgUrl); TextView txtDuree = (TextView)newsView.findViewById(R.id.txtDurationElementVideo); txtDuree.setText("Durée : "+item.duration); txtDuree.setTextColor(Color.rgb(135,154,29)); return newsView; } DownloadImageTask est une ASyncTask qui va simplement télécharger les images et les remplir au fur et à mesure. Je me suis inspiré d'un code sur les AsyncTask sur le blog de dev Android. Lien vers le commentaire Partager sur d’autres sites More sharing options...
popolbx Posté(e) 26 août 2010 Share Posté(e) 26 août 2010 arf ça peut s optimiser mais je vois pas ou ça peut buguer. par contre le telechargement asynchrone, si la tache se finit alors que ta vue a été recyclée...ça te donne la mauvaise image (avant qu'elle soit remplacée). du coup si tyu scroll comme un taré tu lance plein d asynctask qui vont placer des bitmaps dans des vues potentiellement en cours de recyclage. (dangereux). et surtout tu peux en lancer pleins en même temps et faire saturer la mémoire avec trop de bitmaps chargés. Alors qu'en défilant lentement ça devrait aller. Tu devrais mettre tes asynctask dans une file. En gros la fin de la première asynctask lance le début de la suivante. Je ne sais pas si des objets du framework le font. donc en attendant: - fais voir le code de la synctask pour ce qui est des images - regarde quand même la ligne 229 :) Lien vers le commentaire Partager sur d’autres sites More sharing options...
Cuillère Posté(e) 27 août 2010 Auteur Share Posté(e) 27 août 2010 Mon AsyncTask : public class DownloadImageTask extends AsyncTask { private static HashMap listImages = new HashMap(); private final WeakReference imageViewReference; public DownloadImageTask(ImageView imageView){ super(); imageViewReference = new WeakReference(imageView); } @Override protected Drawable doInBackground(String... url) { Drawable d; d = loadImageFromUrl(url[0]); publishProgress(d); return d; } @Override protected void onPostExecute(Drawable d) { if (imageViewReference != null) { ImageView imageView = imageViewReference.get(); if (imageView != null && d !=null) { imageView.setImageDrawable(d); }else{ //imageView.setImageResource(R.drawable.icon); } } this.cancel(true); } public Drawable loadImageFromUrl(String url) { if (!listImages.containsValue(url)) { InputStream inputStream; InputStream inputStreams; Drawable dr = null; try { inputStream = new URL(url).openStream(); dr = Drawable.createFromStream(inputStream, "src"); listImages.put(url, dr); } catch (IOException e) { try { inputStreams = new URL(Main.urlPrefix+"/"+Main.defaultThumbnail).openStream(); dr = Drawable.createFromStream(inputStreams, "src"); listImages.put(url, dr); }catch(Exception ee){ } } return dr; } else { return listImages.get(url); } } } La ligne 229 de quelle Activité ? MenuEcran ? Si c'est le cas, il s'agit simplement de ceci : 229 if(!Main.el.getAttribute("text").equals("")){ TableLayout tab = (TableLayout)findViewById(R.id.tableMenu); TextView textMenuEcran = new TextView(this); textMenuEcran.setText(Main.el.getAttribute("text")); TableRow row = new TableRow(this); row.addView(textMenuEcran); tab.addView(row); } Comment faire pour créer une file pour démarrer mes tâches une après l'autre ? Une piste à suivre ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
Cuillère Posté(e) 27 août 2010 Auteur Share Posté(e) 27 août 2010 Une idée pour la file, j'attends une confirmation pour savoir si c'est faisable avant de me lancer. A la création de ma ListView, crée une ArrayList de String dans laquelle je rentre les url des images à télécharger. Puis lancer un AsyncTask qui prendra le 1er String de la liste et relancera un autre AsyncTask dans son onPostExecute(). C'est faisable ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
popolbx Posté(e) 27 août 2010 Share Posté(e) 27 août 2010 heu ton plantage est ligne 229 de menuecran..... donc là on se fait chier avec les bitmaps depuis 3 jours pour des clous :) donc en gros là: Main.el.getAttribute("text").equals("") ya un truc nul : genre Main ou el ou pas d'attribut text.... j'aurais fait: if(Main.el.getAttribute("text")!=null && !Main.el.getAttribute("text").equals("")){ et contre c'est pas top. par contre tes WeakReference fais gaffe avec. L'image qu'elle contient sera détruite si tu manque de RAM pour ton appli (ou de heap) bref le pb vient pas du tout des images apparement. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Cuillère Posté(e) 30 août 2010 Auteur Share Posté(e) 30 août 2010 J'ai testé, ça ne marche pas. Toujours le même problème. J'essaie de créer une file pour lancer mes AsyncTask. Lien vers le commentaire Partager sur d’autres sites More sharing options...
popolbx Posté(e) 30 août 2010 Share Posté(e) 30 août 2010 si tu veux mais ça ne changera pas grand chose.... si tu le fais en mode debug tu verras l etat des variables au moment du crash. au moins tu sauras quelle partie de ta ligne est à null. Lien vers le commentaire Partager sur d’autres sites More sharing options...
akex Posté(e) 30 août 2010 Share Posté(e) 30 août 2010 Je rejoins popolbx, c'est lié à la ligne 229. Donc debug sur la ligne 229 et celles dans la condition (mets un point d'arrêt) et regarde la valeur de ce que tu compares avec "" Rien à voir avec les images, c'est bien un problème de valeur null sur : soit un élément que tu souhaites alimenter, soit une valeur qui alimente une des views. Concernant les asynctask, oublie tout de suite. Prends exemple sur l'appli contact de Google. Lorsque tu scrolles, tu queue les urls dans un hashmap (imageview --> url). Quand le scroll est IDLE (plus de scroll), tu lances un thread qui se charge de récupérer les images via les urls stockées dans le hashmap. Tu stockes les images dans un cache (softReference par exemple : comme ça le GC gère) que tu alimentes dès lors que l'image n'est pas en cache (soit jamais chargée, soit virée par le GC). Ensuite, quand l'image est chargée dans le cache, tu supprimes l'élément du hashmap. Autre possibilité un stack ... Pense également à tagguer ton imageview avec une donnée propre à l'item (url de l'image par exemple), ça te permettra de charger la bonne image pour chaque item. Si getTag = url de l'image alors c'est que ma vue est visible sur l'écran (sinon écrasée par la nouvelle vue recyclée). Aucun risque d'alimenter quelque chose qui est en cours de recyclage. Et alimente la log dans tes catch exceptions (notamment celui de l'acquisition de l'image via url), ça te permettra de debugguer plus simplement. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Cuillère Posté(e) 31 août 2010 Auteur Share Posté(e) 31 août 2010 Le problème c'est que lors du force/close, je suis dans une autre Activité. C'est pour ça que cette erreur m'est assez incompréhensible. De plus, cette méthode est appelée uniquement dans le onCreate(). Je ne sais pas pourquoi elle provoque cette erreur de pointeur null. J'essaie de tout mettre dans un bloc try/catch ou alors peut-être tagger mon imageView avec l'url de l'image ? Dans ce cas, quelle méthode suivre pour ensuite charger la bonne image pour chaque View ? Merci à vous tous pour l'aide. Lien vers le commentaire Partager sur d’autres sites More sharing options...
popolbx Posté(e) 31 août 2010 Share Posté(e) 31 août 2010 LOL. tu es dans une autre activity. tu explose dans celle qui n'est pas affichée sur le OnCreate.... peut être que justement ton activity reviens sur le devant de la scène. Et ce que tu peux afficher le onCreate qu'on regarde (je sens le multithread foireux). Mets un point d'arret ça ne coute rien et tu verras : 1 - le problème 2 - d'ou est appelé ton onCreate (s'il ne doit pas l etre ça peut cacher un autre problème) 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.