mMap.addPolyline 抛出非法状态异常

Posted

技术标签:

【中文标题】mMap.addPolyline 抛出非法状态异常【英文标题】:mMap.addPolyline throws illegalstateexception 【发布时间】:2013-10-28 21:02:30 【问题描述】:

我有一个服务,它监听位置变化并将消息与 Polylineoptions 一起发送到 UI 线程,它是这样的:

    //some code here
    Bundle bundle = new Bundle();
    bundle.putParcelable("polylineOptions", mPolylineOptions);
    Message msg = Message.obtain(null, LOCATION_UPDATE);
    msg.setData(bundle);
    mMainHandler.dispatchMessage(msg);
    //some more code 

mPolylineOptions 包含新位置以及所有以前的位置。 在主线程中,我有应该更新我的地图的 handleMessage 方法。它是这样的:

    private class MainHandler extends Handler 

     private MainHandler (Looper looper)
         super(looper);
     
     @Override
     public void handleMessage (Message msg)
        switch (msg.what)
        case TrackingService.LOCATION_UPDATE:
            if (D)Log.d(TAG, "Location update received");;
            myPolylineOptions = (PolylineOptions) msg.getData().getParcelable("polylineOptions");
            new Color();
            myPolyline = mMap.addPolyline(myPolylineOptions
                    .color(Color.argb(128, 255, 0, 0))
                    .geodesic(true));
            break;
        
     
 

我可以看到处理程序接收到消息,但我在调用时收到“illegalstateexception: Not On The Main Thread”

    myPolyline = mMap.addPolyline(myPolylineOptions
                .color(Color.argb(128, 255, 0, 0))
                .geodesic(true));

有人知道如何解决这个问题吗? 谢谢!

编辑:

我绑定了服务并将我的 UI 处理程序传递给它,如下所示:

    private ServiceConnection mConnection = new ServiceConnection() 
    // Called when the connection with the service is established
    public void onServiceConnected(ComponentName className, IBinder service) 
        if (D) Log.d(TAG, "main - onServiceConnected started");;
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
        while (mService.getThreadHandler() == null)
            try 
                Thread.sleep(100);
                if(D) Log.d(TAG, "Thread Handler is not ready");;
             catch (Exception e)
        
        mThreadHandler = mService.getThreadHandler();
        mService.setHandler(new MainHandler(Looper.getMainLooper()));

    

线程代码。该线程在服务中运行:

我知道,这个线程类很“肮脏”,不优雅,不专业……

    private class ThreadHandler extends Handler 
        @Override
        public void handleMessage(Message msg) 
            switch (msg.what)
            case MAIN_HANDLER:
                if(D) Log.d(TAG, "main hadler received");;
                break;
            
            super.handleMessage(msg);
        
    

    public LocationThread (Context context)
        mContext = context;
        keepOn = true;
    

    public void cancel() 
        keepOn = false;
        if (D)Log.d(TAG, "thread was canceled");; 
    

    public void run()
        try 
            Looper.prepare();
         catch (Exception e) 
        // create handler for communication
        mThreadHandler = new ThreadHandler();
        // setup location updates
        Location mLocation;
        Location lastLocation = null;
        PolylineOptions mPolylineOptions = new PolylineOptions();
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // Use high accuracy 
        mLocationRequest.setInterval(UPDATE_INTERVAL); // Set the update interval to 5 seconds 
        mLocationRequest.setFastestInterval(FASTEST_INTERVAL); // Set the fastest update interval to 1 second
        mLocationClient = new LocationClient(mContext, this, this);
        mLocationClient.connect();

        while (keepOn)
            try 
                Thread.sleep(10000);
             catch (Exception e)
            if (mConnected)
                if (D) Log.d(TAG, "thread is running");;
                mLocation = mLocationClient.getLastLocation();
                if (lastLocation == null) 
                    LatLng mLatLng = new LatLng(mLocation.getLatitude(), mLocation.getLongitude());
                    mPolylineOptions.add(mLatLng);
                    lastLocation = mLocation;
                
                // Report to the UI that the location was updated
                float distance = mLocation.distanceTo(lastLocation);
                if (distance > 1)
                    LatLng mLatLng = new LatLng(mLocation.getLatitude(), mLocation.getLongitude());
                    mPolylineOptions.add(mLatLng);
                    new Color();
                    lastLocation = mLocation;
                

                if (hasBindedActivity)
                    Bundle bundle = new Bundle();
                    bundle.putParcelable("polylineOptions", mPolylineOptions);
                    Message msg = Message.obtain(null, LOCATION_UPDATE);
                    msg.setData(bundle);
                    mMainHandler.dispatchMessage(msg);
                
            

        

        Looper.loop();
    

【问题讨论】:

根据这段代码,整个 getThreadHandler 对我来说似乎是不必要的。我认为你可以首先为你的 MainHandler 使用没有参数的构造函数(不需要给它循环器)。然后只需从 onServiceConnected(在 UI 线程上运行)调用 mMainHandler = new MainHandler(); 来创建一个新的处理程序。 Hmm.. 在发布此问题之前,我尝试创建 mMainHandler 而没有提供任何循环器。结果还是一样。 你能添加整个代码吗?例如,现在我只能看到 mThreadHandler 正在初始化,但未显示 mMainHandler 的构造函数。 【参考方案1】:

没有主线程就无法更改 UI。 如果你真的想不使用AsyncTask

也许this 会有所帮助。

【讨论】:

好吧,我想我已经在你的链接上实现了类似的东西。而且不知何故它不起作用。我以前也这样做过,但不知道为什么这次不行。【参考方案2】:

对我来说,您的 mMainHandler 似乎是在 GUI 线程之外构建的。确保从 GUI 线程中调用 mMainHandler = new MainHandler();,因为 Handler 回调是在创建 Handler 的线程中执行的。

编辑:正如 Robin 所说,只要您只是计划根据一些后台活动更新 UI,您应该使用例如 AsyncTask 而不是服务。只需在您的Activity 中创建一个扩展AsyncTask 的私有类,在doInBackground 中执行背景操作,然后在onPostExecute 中更新GUI,它会在GUI 线程中再次运行。请参阅http://developer.android.com/reference/android/os/AsyncTask.html 了解更多信息。

【讨论】:

我创建 Handler 并将其传递给我的 onServiceConnected 方法上的服务。可以吗? 感谢有关 asyncTask 的建议,但这次我真的需要服务。任何想法为什么我的实施不起作用?我是否以正确的方式创建 Handler? 好的,但是为什么您需要为此提供服务呢?无论如何,这里还有一个可能有帮助的问题:***.com/questions/14695537/… 即使在应用程序被杀死后,服务也应该监听位置更新。我知道,也许这不是一个好主意,因为耗电量,也许还有其他方法可以在没有服务的情况下做到这一点,但我觉得我快要完成了,我只需要在收到位置更新后更新我的 UI。跨度> 但如果应用不再可见,则无需更新 GUI。所以我会尝试解耦逻辑:使用服务来接收位置更新并将该信息存储在某处(例如数据库)。然后在您的 GUI 代码中,例如,AsyncTask 检查是否有可用的新信息并相应地更新 GUI。【参考方案3】:

显然是命令 mMainHandler.dispatchMessage(msg);在错误的线程(工作线程)上执行 Handlers 的 handleMessage 方法。文档说 "dispatchMessage(Message msg) 在此处处理系统消息。” 我必须使用 sendMessage(Message msg) “在当前时间之前的所有待处理消息之后,将消息推送到消息队列的末尾。”

【讨论】:

以上是关于mMap.addPolyline 抛出非法状态异常的主要内容,如果未能解决你的问题,请参考以下文章

Crashlytics.logException 方法抛出非法状态异常。无法收集某些活动的非致命问题

获取 mediaMetadataRetriever.setDataSource 抛出非法参数异常

mediaMetadataRetriever.setDataSource(getBaseContext(),uri) 抛出非法参数异常

Jenkins Pipeline正在抛出非法争论异常

渲染模板期间抛出异常(“警告:isset 中的偏移类型非法或为空”)

浅析c++异常