0

Mon application fonctionne très bien avec Android 1.6, mais quand je l'exécute sur Android 2.2, je reçois concurrModificationException à certains endroits. Après avoir enveloppé ma tête pendant des jours, j'ai trouvé une théorie: je suppose que le multi-threading (ou quelque chose de similaire) a été introduit depuis la version 1.6. Cela pourrait-il être cela? Si oui, est-ce un moyen de forcer l'application à s'exécuter sans le multi-thread? J'ai essayé de fixer la cible à 1,6, mais pas de chance ... D'avance, je voudrais vous remercier pour votre temps.Android mise à niveau de 1,6 à 2,2 entraîne des exceptions

Exception:

04-05 11:47:12.812: ERROR/AndroidRuntime(5328): FATAL EXCEPTION: main 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { cmp=ntnu.client/com.google.android.maps.MapView (has extras) }} to activity {ntnu.client/ntnu.client.MapClient}: java.util.ConcurrentModificationException 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.app.ActivityThread.deliverResults(ActivityThread.java:3808) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.app.ActivityThread.handleSendResult(ActivityThread.java:3850) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.app.ActivityThread.access$2800(ActivityThread.java:136) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2209) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.os.Handler.dispatchMessage(Handler.java:99) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.os.Looper.loop(Looper.java:143) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.app.ActivityThread.main(ActivityThread.java:5068) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at java.lang.reflect.Method.invokeNative(Native Method) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at java.lang.reflect.Method.invoke(Method.java:521) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at dalvik.system.NativeStart.main(Native Method) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328): Caused by: java.util.ConcurrentModificationException 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at ntnu.client.MapClient.handleResult(MapClient.java:599) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at ntnu.client.MapClient.onActivityResult(MapClient.java:881) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.app.Activity.dispatchActivityResult(Activity.java:3988) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at android.app.ActivityThread.deliverResults(ActivityThread.java:3804) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  ... 11 more 

Code avec handleResult-code est fourni ci-dessous.

public synchronized void handleResult(boolean notify) 
    { 

     if(!citynodes.equals(null) && citynodes.size()>0) 
     { 
      noteBaloon.setVisibility(0x00000008); 

      Drawable drawable = this.getResources().getDrawable(R.drawable.up); 
      Context myContext = this; 

      itemizedoverlay = new CitynodeItemizedOverlay(drawable,myContext); 
      itemizedoverlay.setThumbsUp(BitmapFactory.decodeResource(
        getResources(), R.drawable.vote_yes3)); 

      itemizedoverlay.setThubmsDown(BitmapFactory.decodeResource(
        getResources(), R.drawable.vote_no3)); 
      itemizedoverlay.addObserver(this);  

      //itemizedoverlay.setDoAnimtation(true); 

      RecommendationNotificationOverlay overlay = new RecommendationNotificationOverlay(); 


      for (Recommendation n : citynodes) 
      { 

       CitynodeOverlayItem cn= n.getNode().getOverlayItem(); 
       Drawable marker = this.iconmanager.changeBackground(this.iconmanager.findIcon(n.getNode()),Integer.parseInt(n.getSystemRating()),n.isPersonalized()); 
       //marker.setAlpha(100); 
       marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight()); 

       ShapeDrawable l; 

       cn.setMarker(marker); 
       cn.setNode(n); 
       itemizedoverlay.addOverlay(cn); 

       LayoutInflater inflater = getLayoutInflater(); 
      } 



      for(Overlay i : getMapView().getOverlays()) 
      { 
       if((i instanceof ItemizedOverlay)) //|| (i instanceof RecommendationNotificationOverlay)) 
        this.mapView.getOverlays().remove(i); 
      } 



      for(Overlay i : getMapView().getOverlays()) 
      { 
       if((i instanceof RecommendationNotificationOverlay)) 
        this.mapView.getOverlays().remove(i); 
      } 
      List <Recommendation> proactive = new ArrayList<Recommendation>(); 

      for(Recommendation potpro : this.citynodes) 
      { 
       if(potpro.isProactive()) 
       { 
        proactive.add(potpro); 

       } 

      } 

      overlay.setNotifications(proactive); 

      mapOverlays.add(overlay); 



      mapOverlays.add(itemizedoverlay); 



      mapView.invalidate(); 

     } 

    } 

Le code de cette exception fait référence est la première boucle for:

for(Overlay i : getMapView().getOverlays()) 

Le code jette également la même exception à cette ligne (traitement une autre action):

if(!citynodes.equals(null) && citynodes.size()>0) 
+0

pouvez-vous fournir le journal de ces erreurs? puisque la mise à niveau vers la version 2.2 à partir de la version 1.6 ne devrait pas poser de problème –

+0

L'erreur n'est pas due à thread.did vous avez une erreur dans vos programmes? –

+0

Android a toujours eu le multithreading, mais 2.2 introduit JIT qui donne quelques améliorations de vitesse, et peut avoir causé le minutage entre vos threads de changer où précédemment vous avez eu la chance qu'il n'a pas montré sa tête. – Nick

Répondre

1

Ah, au moins un de vos problèmes est rien à voir avec multithreading:

for(Overlay i : getMapView().getOverlays()) 
{ 
    if (i instanceof ItemizedOverlay) 
     this.mapView.getOverlays().remove(i); 
} 

Vous ne pouvez pas modifier une collection alors que nous parcourons dessus avec ce style de for-loop. Parfois, la mise en œuvre de la collection ne remarquera pas et vous vous en tirerez, mais je soupçonne que l'implémentation des collections aurait pu être modifiée à un moment donné dans Android, ce qui attraperait ce genre de chose. Si vous souhaitez supprimer des éléments en boucle, vous devez obtenir un Iterator et l'utiliser pour boucler, en appelant remove sur le Iterator.

for(Iterator<Overlay> it=getMapView().getOverlays().iterator(); it.hasNext();) 
{ 
    Overlay i = it.next(); 
    if (i instanceof ItemizedOverlay) 
     it.remove(); 
} 

Ou quelque chose à cet effet.

+0

J'aurais dû le remarquer plus tôt - 'ConcurrentModificationException' signifie généralement que quelque chose comme ça s'est produit. Lorsque deux threads modifient une collection en même temps, vous avez tendance à obtenir des exceptions plus déroutantes. – Nick

0

C'est la partie du message d'erreur qui vous intéresse:

04-05 11:47:12.812: ERROR/AndroidRuntime(5328): Caused by: java.util.ConcurrentModificationException 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at ntnu.client.MapClient.handleResult(MapClient.java:599) 
04-05 11:47:12.812: ERROR/AndroidRuntime(5328):  at ntnu.client.MapClient.onActivityResult(MapClient.java:881) 

L'erreur se produit à la ligne 599 de la classe MapClient dans la méthode handleResult. Pourriez-vous poster le code de votre méthode handleResult?

L'exception est due au fait que plusieurs threads tentent de modifier l'ArrayList en même temps.

+0

J'ai regardé ce code. Il n'a pas obtenu med n'importe où .. Mais alors comment est-ce que l'application fonctionne sur 1.6 mais pas 2.2? Il échoue à chaque fois en 2.2, et jamais en 1.6 .. – pecka85

0

Enveloppez sychronized ([ArrayList]) {} autour des zones où vous modifiez le contenu du tableau. De cette façon, les fils sont tous deux capables de changer le contenu Array

+0

Je vais essayer cet après-midi. La méthode qui lance l'exception est synchronisée (voir le code ci-dessus), cela n'aurait-il pas dû être le cas dans un tel cas? – pecka85

+0

@ pecka85 - une de ces listes est-elle partagée entre les instances de cette classe? 'synchronized' sur une méthode se synchronise uniquement sur cette instance d'objet, donc si elles partagent les mêmes données, elles pourraient encore faire des choses dangereuses. – Nick

+0

@Nick Il n'existe qu'une seule instance de cette classe (activité). Cependant, une classe (activité) assez similaire existe mais même sans démarrer cette autre activité, l'activité principale plante. – pecka85

Questions connexes