androidexceptionupgradeandroid-2.2-froyoandroid-1.6-donut

Android upgrade from 1.6 to 2.2 results in exceptions


My application works fine with Android 1.6, but when I run it on Android 2.2 I get concurrentModificationException in some places. After wrapping my head around it for days, I've come up with a theory: I guess that multi-threading (or something similar) has been introduced since 1.6. Could this be it? If so, is it any way to force the application to be run without the multi-threading? I've tried to set the target to 1.6, but no luck.. In advance, I'd like to thank you for your time.

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 with handleresult-code is provided below.

  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();

      }

  }  

The code this Exception refers to is the first for-loop:

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

The code also throws the same Exception on this line (processing another action):

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

Solution

  • Ah, at least one of your problems is nothing to do with multithreading:

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

    You can't modify a collection while you're iterating over it with this style of for-loop. Sometimes the collection implementation won't notice and you'll get away with it, but I suspect the implementation of collections could have been changed at some point in Android which would catch this sort of thing. If you want to remove items while looping, you'll need to get an Iterator and use that to loop, calling remove on the Iterator.

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

    Or something to that effect.