Aller au contenu

Force close après l'affichage d'une ListView


Cuillère

Recommended Posts

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

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

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

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

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

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

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

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

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

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

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...