ui线程之间的快速切换迫使app突然终止

时间:2014-10-18 21:58:57

标签: android multithreading user-interface

我正在制作一个手电筒应用程序,其中我放置了两个切换按钮,两个切换按钮的功能是

1)给予频闪(sos)效果。 EnableStrobe / DisableStrobe。

2)简单的手电筒效果。 EnableFlashlight / DisableFlashlight。

如果我单独切换这些ToggleButtons或在这些切换之间慢慢切换ToggleBUttonsthen我的应用程序工作正常。但快速切换这些切换按钮我的应用程序突然终止。我已经为每个ToggleButton创建了两个线程类。事情正在发挥作用,我觉得我的onClickListener代码存在一些问题。

主要ui线程中的

onClickListener代码

strobebutton.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            if (flag1 == 1) {
                flasheffect.isflashOn = true;
                flashbutton.setChecked(false);
            }
            if (strobebutton.isChecked()) {
                bw = new Thread(strobeffect);
                bw.start();
                flag2 = 1;
            } else {
                strobeffect.requestStop = true;
            }
        }
    });
    flashbutton.setOnClickListener(new OnClickListener() {
        public void onClick(View arg0) {
            if (flag2 == 1) {
                runner.requestStop = true;
                strobeffect.setChecked(false);
            }
            if (togglebutton1.isChecked()) {
                aw = new Thread(flasheffect);
                aw.start();
                flag1 = 1;
            } else {
                flasheffect.isflashOn = true;
            }
        }
    });

与StrobeClass关联的ToggleButton

public class StrobeRunner implements Runnable {
protected StrobeRunner() {
}

public static StrobeRunner getInstance() {
    return (instance == null ? instance = new StrobeRunner() : instance);
}

private static StrobeRunner instance;
public volatile boolean requestStop = false;
public volatile boolean isRunning = false;
public volatile int delay = 10;
public volatile int delayoff = 10;
public volatile StrobeLightConfig controller;
public volatile String errorMessage = "";

public void run() {
    if (isRunning)
        return;

    requestStop = false;
    isRunning = true;

    Camera cam = Camera.open();

    Camera.Parameters pon = cam.getParameters(), poff = cam.getParameters();

    pon.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
    poff.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);

    while (!requestStop) {
        try {
            cam.setParameters(pon);
            Thread.sleep(delay);
            cam.setParameters(poff);
            Thread.sleep(delayoff);
        } catch (InterruptedException ex) {

        } catch (RuntimeException ex) {
            requestStop = true;
            errorMessage = "Error setting camera flash status. Your device may be unsupported.";
        }
    }
    cam.release();
    isRunning = false;
    requestStop = false;
    controller.mHandler.post(controller.mShowToastRunnable);
}

}

使用FlashEffect类的代码

public class FlashOn implements Runnable {

protected FlashOn() {
}

public static FlashOn getInstance() {
    return (instance == null ? instance = new FlashOn() : instance);
}

private static FlashOn instance;
public volatile StrobeLightConfig control;
public volatile boolean isflashOn = false;
public volatile boolean isRunning = false;
public volatile String errMessage = "";
Parameters param;

public void run() {
    if (isRunning) {
        return;
    }
    isRunning = true;
    isflashOn = false;
    Camera camera = Camera.open();
    param = camera.getParameters();
    param.setFlashMode(Parameters.FLASH_MODE_TORCH);
    while (!isflashOn) {
        try {
            camera.setParameters(param);
        } catch (RuntimeException e) {
            isflashOn = true;
        }
    }
    camera.release();
    isflashOn = false;
    isRunning = false;
}

}

logcat的

10-19 03:37:29.521: E/AndroidRuntime(27146): FATAL EXCEPTION: Thread-16457
10-19 03:37:29.521: E/AndroidRuntime(27146): Process: com.stwalkerster.android.apps.strobelight, PID: 27146
10-19 03:37:29.521: E/AndroidRuntime(27146): java.lang.RuntimeException: Fail to connect to camera service
10-19 03:37:29.521: E/AndroidRuntime(27146):    at android.hardware.Camera.native_setup(Native Method)
10-19 03:37:29.521: E/AndroidRuntime(27146):    at android.hardware.Camera.<init>(Camera.java:364)
10-19 03:37:29.521: E/AndroidRuntime(27146):    at android.hardware.Camera.open(Camera.java:334)
10-19 03:37:29.521: E/AndroidRuntime(27146):    at com.stwalkerster.android.apps.strobelight.FlashOn.run(FlashOn.java:28)
10-19 03:37:29.521: E/AndroidRuntime(27146):    at java.lang.Thread.run(Thread.java:841)

我的问题可能很愚蠢,但我已经坚持了很长一段时间。

谢谢

2 个答案:

答案 0 :(得分:0)

看起来你的下一个线程正在尝试打开相机,而前一个尚未发布它,添加日志以验证它。您的线程同步代码可能有问题,下一个线程应始终只在前一个线程停止后启动。使用ExecutorService应该可以很容易地实现从队列中执行一个runnable。

我认为你可以保留一个全局活动Camera对象并在onStart中打开它并在onPause中释放,或者至少在某个全局实例或类上同步你的线程。

答案 1 :(得分:0)

我建议每个活动只使用一个Camera对象。因为你的线程正在使用不同的Camera对象一个线程正在尝试打开相机,而另一个线程尚未释放它并且快速切换会导致Fail to connect to camera service

<强>原因:

根据 android camera open documentation ,会抛出运行时异常:

  

如果与相机服务的连接失败(例如,如果相机正在被其他进程使用或设备策略管理器已禁用相机)

如何实现

在Activity中创建一个( only )相机对象,并使用Thread类的构造函数 getter setter将Pass Camera Object传递给Runnable类。