解析数据时出错 java.lang.IllegalStateException:尝试添加标记时不在主线程上

Error Parsing Data java.lang.IllegalStateException: Not on the main thread when trying to add a marker

我正在尝试使用服务更新 Google 地图上的标记,但是当我使用 "setParkingSpotMarker" 函数为列表中的每个项目添加标记时,出现错误 "java.lang.IllegalStateException: Not on the main thread"

函数"setParkingSpotMarker"在服务-DataUpdateService的循环中被调用。

我不知道如何更改我的代码,所以它会更新主要的标记 thread.I 已经阅读了一些相关的帖子,但不明白如何在我的代码中更改它。

这是服务:

 package com.example.sailon;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    import android.util.Log;
    import java.util.ArrayList;
    import java.util.Timer;
    import java.util.TimerTask;

import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;

public class DataUpdateService extends Service {
    Timer myTimer = new Timer();
    MyTimerTask myTask = new MyTimerTask();
    MyMap mymap;
    String teamID;
    static LatLng teamLocation;
    ArrayList<TeamsList> teamsList= new ArrayList<TeamsList>() ;
    public ArrayList<UnitInHeatForMap> unitswithteam= new ArrayList<UnitInHeatForMap>();
    String action;
    Context fromContext;
   String CompName;
   String heatNum;
   boolean isSailor;
   String usermail;
   GPSTracker gps;


    private final IBinder mBinder = new LocalBinder();

    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("PS", "DataUpdateService onStartCommand");
        return Service.START_NOT_STICKY;
    }

    @Override
    // return thee instance of  the local binder to the activity
    public IBinder onBind(Intent intent) {
        Log.d("PS", "DataUpdateService onBind");
        return mBinder;
    }

    public class LocalBinder extends Binder {
        DataUpdateService getService() {
            Log.d("PS", "DataUpdateService LocalBinder onBind");
            return DataUpdateService.this;
        }
    }

    public class MyTimerTask extends TimerTask {
        @Override
        public void run() {
            String unitToUpdate= mymap.getUnitToUpdate (CompName,heatNum,usermail);
            Log.d("NY","CompName " +CompName);
            Log.d("NY","heatNum " +heatNum);
            Log.d("NY","usermail " +usermail);

            Log.d("NY","unitToUpdate" +unitToUpdate);

            Log.d("NY","isSailor" +isSailor);
            if (isSailor){
                gps = new GPSTracker(DataUpdateService.this,unitToUpdate );
                if( ! (gps.canGetLocation())){      
                     gps.showSettingsAlert();
                 }
            }

            unitswithteam=mymap.refresh (CompName,heatNum);

            int j= unitswithteam.size();
            for (int i=0; i<j;i++){   
                teamID=unitswithteam.get(i).getTeamID(); 
                Log.d("NY","teamID "+i+teamID);
                UnitsInHeats us=unitswithteam.get(i).getUnit();
                teamLocation = new LatLng(us.getLat(),us.getLng() );
                Log.d("NY","team location "+i + " "+us.getLat());
                mymap.setParkingSpotMarker(teamLocation,teamID);

                if (i==(j-1)){
                    CameraPosition secound =new CameraPosition.Builder()
                    .target(teamLocation)
                    .zoom(15.5f)
                    .bearing(300)
                    .tilt(50)
                    .build();
                    mymap.moveMyMapCamera(secound);
                 }
        }

        }
    }

    // called from the activity
    public void MapUpdateFromService(Context context, MyMap map, final String action,
                                String CompName, String heatNum, boolean isSailor , String usermail) {
        Log.d("PS", "DataUpdateService MapUpdateFromService");
        this.mymap = map;
        this.action = action;
        this.CompName=CompName;
        this.heatNum=heatNum;
        this.isSailor=isSailor;
        this.usermail=usermail;

        // this command activate the run function from the inner class MyTimerTask every 5 seconds.
        myTimer.schedule(myTask,0,5000);
    }


    public void onDestroy() {
        super.onDestroy();
        // cancel the scheduler.
        myTimer.cancel();
    }
}

这是调用服务的activity:

package com.example.sailon;
import java.util.ArrayList;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import android.app.ActionBar;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class Map extends Activity {
    Bundle extras;
//  private GoogleMap map;
    static LatLng teamLocation;
    //public static ArrayList<Teams> teams;
    ArrayList<TeamsList> teamsList= new ArrayList<TeamsList>() ;
    Marker mark;
    double lat;
    double lng;
    GPSTracker gps;
    String Location ;
    String teamID;
    String CompName;
    MyMap mymap;
    String heatNum;
    String CompID;
    boolean isSailor;
    String usermail;
    static LatLng BeerSheva = new LatLng(31.250919, 34.783916);
    public ArrayList<UnitInHeatForMap> unitswithteam= new ArrayList<UnitInHeatForMap>();
//  ArrayList<LatLng> List= new ArrayList<LatLng>() ;
    DataUpdateService dbuService;
    boolean dbuBound=false;// when service connected get true

    @Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);
        mymap= new MyMap(this,((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap());
        //map=((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();

        extras = getIntent().getExtras();
        CompName=extras.getString("CompName");
        heatNum=extras.getString("heatNum");
        isSailor=extras.getBoolean("isSailor");
        usermail=extras.getString("usermail");
        Log.d("CompName",CompName);
        Log.d("heatNum",heatNum);
        // get action bar   
        ActionBar actionBar = getActionBar();
        // Enabling Up / Back navigation
        actionBar.setDisplayHomeAsUpEnabled(true);


        if (mymap!=null){
            Log.d("PS", "map isnt null");
            mymap.setMapType();
            mymap.setMyLocationEnabled(true);
            CameraPosition firstZom =new CameraPosition.Builder()
            .target(BeerSheva)
             .zoom(15.5f)
             .bearing(300)
            .tilt(50)
            .build();

            mymap.moveMyMapCamera(firstZom);
        }



    }



        // serviceConnerction is an interface that must be implemented when using bound service
        private ServiceConnection sConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d("PS", "Map onServiceConnected");
                DataUpdateService.LocalBinder binder=(DataUpdateService.LocalBinder)service;
                dbuService=binder.getService();
                Log.d("PS", "Map callupdate");
                dbuService.MapUpdateFromService(Map.this,mymap,"ActionSearch",CompName,heatNum, isSailor,usermail);
                dbuBound=true;
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d("PS", "Map onServiceDisconnected");
                dbuBound=false;
            }
        };

        @Override
        protected void onStart() {
            super.onStart();
            // Bind to DataUpdateService
            Log.d("PS", "Map onStart");
            Intent intent= new Intent(this,DataUpdateService.class);
            bindService(intent,sConnection, Context.BIND_AUTO_CREATE);
        }

        @Override
        protected void onStop() {
            super.onStop();
            // Unbind from the service
            Log.d("PS", "Map onStop");
            if(dbuBound){
                unbindService(sConnection);
                dbuBound=false;
            }
        }
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.activity_main_actions, menu);

        return super.onCreateOptionsMenu(menu);
    }   

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Take appropriate action for each action item click
        switch (item.getItemId()) {
        case R.id.logoutAction:     
            Intent i = new Intent(Map.this, MainActivity.class);
            startActivity(i);
            return true;
        case R.id.VideoAction:      
            Intent intent = new Intent("android.media.action.VIDEO_CAMERA");
            startActivity(intent);
            return true;
        case R.id.CallAction:      
           Intent call = new Intent(Intent.ACTION_DIAL);
           startActivity(call);
            return true; 
        default:
            return super.onOptionsItemSelected(item);
        }
    }


}

这是地图的等级: 包裹 com.example.sailon;

import android.content.Context;

import android.util.Log;


import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;

import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;

import com.google.android.gms.maps.model.MarkerOptions;
import com.parse.ParseException;

import java.util.ArrayList;


/**
 * Created by Evyatar.m on 21/02/2015.
 */
public class MyMap {

    private GoogleMap map;
    static LatLng BeerSheva = new LatLng(31.250919, 34.783916);
    String CompID;
    String teamID;
    String CompName;
    String heatNum;
    ArrayList<TeamsList> teamsList= new ArrayList<TeamsList>() ;
    public ArrayList<UnitInHeatForMap> unitswithteam2= new ArrayList<UnitInHeatForMap>();
    static LatLng teamLocation;
    Model DB;


    public MyMap(Context context, GoogleMap map) {
        Log.d("PS", "MyMap builder");
        DB = Model.getInstance(context);
        this.map = map;

    }

    public String getUnitToUpdate (String CompName,String heatNum, String usermail){
        String unit=null;
        try {   
            CompID= DB.getCompIDByName(CompName);       
        } catch (com.parse.ParseException e) {      
            e.printStackTrace();
        }
        try {
            unit= DB.getUnitToUpdateFromDB (CompID,heatNum, usermail);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return unit;
    }
    public void setMyLocationEnabled(boolean b){
        Log.d("PS", "MyMap set location enable");
        map.setMyLocationEnabled(true);
    }


    public void setParkingSpotMarker(LatLng teamLocation,String teamID) {
        Log.d("PS", "ParkingMap setParkinSpotMarker");
        map.addMarker(new MarkerOptions()
                .position(teamLocation)
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.iconsmall))
                .title("Team " +teamID)).showInfoWindow();


    }

    public void setMapType(){
        Log.d("PS", "MyMap setType");
    map.setMapType(GoogleMap.MAP_TYPE_NORMAL);  
    }

    public void moveMyMapCamera(CameraPosition firstZom) {
        Log.d("PS", "MyMap moveParkingMapCamera");
        map.moveCamera(CameraUpdateFactory.newCameraPosition(firstZom));
    }
  //updates all points on map

    public ArrayList<UnitInHeatForMap> refresh (String CompName,String heatNum){
        Log.d("PS", "MyMap refresh");
        try {   
            CompID= DB.getCompIDByName(CompName);       
        } catch (com.parse.ParseException e) {      
            e.printStackTrace();
        }

        try {
            DB.setUnitInHeatForMap (new Model.CallbackModel () {
                @Override
                public void done (ArrayList<UnitInHeatForMap> unitswithteam){
                    if (unitswithteam.size() >0){
                        unitswithteam2=unitswithteam;
                    }

                }
            }, CompID, heatNum,this);

        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        return  unitswithteam2;



 }


}

请帮帮我 谢谢 !!!**

TimerTaskrun方法在后台线程运行,只能在主线程更新地图。

所以你必须把下面的MapUI更新代码包装成runOnUiThread()

        mymap.setParkingSpotMarker(teamLocation,teamID);

        if (i==(j-1)){
            CameraPosition secound =new CameraPosition.Builder()
            .target(teamLocation)
            .zoom(15.5f)
            .bearing(300)
            .tilt(50)
            .build();
            mymap.moveMyMapCamera(secound);
         }

你需要有一个 Activity 来应用 runOnUI 线程,所以你需要把你的

fromContext = ((Map)context);

在您的 MapUpdateFromService 方法的第一行内。然后您可以在 TimerTaskrun() 方法中调用 runOnUiThread()

((Map)fromContext).runOnUiThread(new Runnable() {
    @Override
    public void run() {
       //run your Map UI update code
    }
});

这也是this problem的类似问题。