SurfaceView Thread IllegalMonitorStateException

时间:2013-12-07 05:19:32

标签: java android multithreading surfaceview

我试图将我的程序的两个部分放在一起。我有一张地图,用户可以四处移动并点击地图的某些部分。然后它将它们带到一个新的活动,显示他们按下的信息。显示信息时出现错误。它启动活动并暂时显示它,但随后重新启动MainActivity。错误似乎出现在我的SurfaceView类中。

public class MapSurface extends SurfaceView implements SurfaceHolder.Callback {
    private static MapSurface rs;
    private Context c;
    private SurfaceHolder sh;

    private RenderSurfaceThread render_thread;

    private static Map map;

    public MapSurface(Context context, AttributeSet attr) {
        super(context, attr);

        c = context;
        sh = getHolder();

        sh.addCallback(this);

        render_thread = new RenderSurfaceThread();

        setFocusable(true);
    }

    public static MapSurface getInstance() {
        return rs;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        rs = this;
        map = new Map(c.getResources(), R.drawable.map, getWidth(), getHeight());
        render_thread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        render_thread.stopThread();
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        return MapTouchHandler.handleTouch(this, map, e);
    }

    public final Map getMap() {
        return map;
    }

    public void requestRedraw() {
        render_thread.throttleThread();
    }

    public int getState() {
        return render_thread.thread_state;
    }

    public RenderSurfaceThread getThread() {
        return render_thread;
    }

    class RenderSurfaceThread extends Thread {

        // Some thread state variables.
        public static final int THREAD_UNDEFINED = -1;
        public static final int THREAD_NEW = 0;
        public static final int THREAD_IDLE = 1;
        public static final int THREAD_EXECUTING = 2;
        public static final int THREAD_KILL = 3;
        public static final int THREAD_DEAD = 4;

        // Thread state variable.
        private int thread_state = THREAD_UNDEFINED;

        // Idle lock object
        private final Object RUN_LOCK = new Object();

        private RenderSurfaceThread() {
            setState(THREAD_NEW);
        }

        @Override
        public void run() {
            setState(THREAD_EXECUTING);

            while (thread_state != THREAD_KILL) {
                map.transformImage();
                doDraw();

                // Thread will idle until redraw is requested.
                idleThread();
            }

            setState(THREAD_DEAD);
        }

        private void doDraw() {
            Canvas canvas = null;
            try {
                canvas = sh.lockCanvas(null);
                synchronized (sh) {
                    // Critical section. Do not allow mRun to be set false until
                    // we are sure all canvas draw operations are complete.
                    //
                    // If mRun has been toggled false, inhibit canvas
                    // operations.
                    synchronized (RUN_LOCK) {
                        if (thread_state == THREAD_EXECUTING) {
                            // Do our drawing here
                            canvas.drawBitmap(map.getMapBitmap(), 0, 0, null);
                        }
                    }
                }
            } finally {
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                if (canvas != null) {
                    sh.unlockCanvasAndPost(canvas);
                }
            }
        }

        private void idleThread() {
            setState(THREAD_IDLE);
            try {
                do {
                    synchronized (sh) {
                        sh.wait();
                    }
                } while (thread_state != THREAD_EXECUTING); // Ensure the notify
                                                            // means that it is
                                                            // time to execute
                // and not something else
            } catch (InterruptedException e) {
            }
        }

        private void throttleThread() {
            synchronized (sh) {
                setState(THREAD_EXECUTING);
                sh.notifyAll();
            }
        }

        private void setState(int state) {
            synchronized (sh) {
                synchronized (RUN_LOCK) {
                    assert (thread_state != THREAD_DEAD);
                    thread_state = state;
                    RUN_LOCK.notifyAll();
                }
            }
        }

        private void stopThread() {
            // we have to tell thread to shut down & wait for it to finish, or
            // else
            // it might touch the Surface after we return and explode
            boolean retry = true;
                do {
                    if (thread_state == THREAD_IDLE) {
                        setState(THREAD_KILL);
                        throttleThread();
                    } else {
                        try {
                            RUN_LOCK.wait();
                        } catch (Exception e) {
                        }
                    }
                } while (thread_state != THREAD_KILL
                        && thread_state != THREAD_DEAD);

                while (retry) {
                    try {
                        join();
                        retry = false;
                    } catch (InterruptedException e) {
                    }
                }

        }
    }
}

Logcat输出:

12-07 00:16:18.235: E/AndroidRuntime(2721): FATAL EXCEPTION: main
12-07 00:16:18.235: E/AndroidRuntime(2721): java.lang.IllegalMonitorStateException: object not locked by thread before wait()
12-07 00:16:18.235: E/AndroidRuntime(2721):     at java.lang.Object.wait(Native Method)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at java.lang.Object.wait(Object.java:364)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at com.eecs448.kuville.ui.MapSurface$RenderSurfaceThread.stopThread(MapSurface.java:183)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at com.eecs448.kuville.ui.MapSurface$RenderSurfaceThread.access$1(MapSurface.java:171)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at com.eecs448.kuville.ui.MapSurface.surfaceDestroyed(MapSurface.java:53)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.SurfaceView.updateWindow(SurfaceView.java:555)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:232)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.View.dispatchWindowVisibilityChanged(View.java:7682)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1227)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1004)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5481)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.Choreographer.doCallbacks(Choreographer.java:562)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.Choreographer.doFrame(Choreographer.java:532)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.os.Handler.handleCallback(Handler.java:730)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.os.Handler.dispatchMessage(Handler.java:92)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.os.Looper.loop(Looper.java:137)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at android.app.ActivityThread.main(ActivityThread.java:5103)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at java.lang.reflect.Method.invokeNative(Native Method)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at java.lang.reflect.Method.invoke(Method.java:525)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
12-07 00:16:18.235: E/AndroidRuntime(2721):     at dalvik.system.NativeStart.main(Native Method)
12-07 00:16:18.285: E/InputDispatcher(1201): channel 'b1404ba8 com.eecs448.kuville/com.eecs448.kuville.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
12-07 00:16:18.285: E/InputDispatcher(1201): channel 'b15a72b8 com.eecs448.kuville/com.eecs448.kuville.Building (server)' ~ Channel is unrecoverably broken and will be disposed!
12-07 00:16:18.285: E/InputDispatcher(1201): channel 'b158bbf8 com.eecs448.kuville/com.eecs448.kuville.main.MapActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
12-07 00:16:18.335: E/JavaBinder(1201): *** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
12-07 00:16:18.335: E/JavaBinder(1201): java.lang.IndexOutOfBoundsException: Invalid index 4, size is 4
12-07 00:16:18.335: E/JavaBinder(1201):     at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
12-07 00:16:18.335: E/JavaBinder(1201):     at java.util.ArrayList.get(ArrayList.java:308)
12-07 00:16:18.335: E/JavaBinder(1201):     at com.android.server.am.ActivityManagerService.handleAppCrashLocked(ActivityManagerService.java:8351)
12-07 00:16:18.335: E/JavaBinder(1201):     at com.android.server.am.ActivityManagerService.makeAppCrashingLocked(ActivityManagerService.java:8221)
12-07 00:16:18.335: E/JavaBinder(1201):     at com.android.server.am.ActivityManagerService.crashApplication(ActivityManagerService.java:8900)
12-07 00:16:18.335: E/JavaBinder(1201):     at com.android.server.am.ActivityManagerService.handleApplicationCrashInner(ActivityManagerService.java:8455)
12-07 00:16:18.335: E/JavaBinder(1201):     at com.android.server.am.ActivityManagerService.handleApplicationCrash(ActivityManagerService.java:8437)
12-07 00:16:18.335: E/JavaBinder(1201):     at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:1211)
12-07 00:16:18.335: E/JavaBinder(1201):     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1737)
12-07 00:16:18.335: E/JavaBinder(1201):     at android.os.Binder.execTransact(Binder.java:388)
12-07 00:16:18.335: E/JavaBinder(1201):     at dalvik.system.NativeStart.run(Native Method)
12-07 00:16:18.335: E/ActivityManager(1201): Activity Manager Crash
12-07 00:16:18.335: E/ActivityManager(1201): java.lang.IndexOutOfBoundsException: Invalid index 4, size is 4
12-07 00:16:18.335: E/ActivityManager(1201):    at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
12-07 00:16:18.335: E/ActivityManager(1201):    at java.util.ArrayList.get(ArrayList.java:308)
12-07 00:16:18.335: E/ActivityManager(1201):    at com.android.server.am.ActivityManagerService.handleAppCrashLocked(ActivityManagerService.java:8351)
12-07 00:16:18.335: E/ActivityManager(1201):    at com.android.server.am.ActivityManagerService.makeAppCrashingLocked(ActivityManagerService.java:8221)
12-07 00:16:18.335: E/ActivityManager(1201):    at com.android.server.am.ActivityManagerService.crashApplication(ActivityManagerService.java:8900)
12-07 00:16:18.335: E/ActivityManager(1201):    at com.android.server.am.ActivityManagerService.handleApplicationCrashInner(ActivityManagerService.java:8455)
12-07 00:16:18.335: E/ActivityManager(1201):    at com.android.server.am.ActivityManagerService.handleApplicationCrash(ActivityManagerService.java:8437)
12-07 00:16:18.335: E/ActivityManager(1201):    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:1211)
12-07 00:16:18.335: E/ActivityManager(1201):    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1737)
12-07 00:16:18.335: E/ActivityManager(1201):    at android.os.Binder.execTransact(Binder.java:388)
12-07 00:16:18.335: E/ActivityManager(1201):    at dalvik.system.NativeStart.run(Native Method)

2 个答案:

答案 0 :(得分:0)

相反做这个MapSurface法术。为什么不选择Google Map v2。

https://developers.google.com/maps/documentation/android/

在其上添加任何类型的Marker并倾听他们的行动并做任何你想做的事。

地图是3d,地图部分就像魅力一样。

答案 1 :(得分:0)

确保你像这样处理onSaveInstanceState

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putBoolean("inprogress", true);
    super.onSaveInstanceState(outState);
}

@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    boolean isNew = true;
    if(savedInstanceState != null)
        isNew = !savedInstanceState.getBoolean("inprogress");
    initActivity(isNew);
}

您需要区分在应用开始时或保存配置后创建的主要活动