您需要确保在活动暂停或暂停时松开相机。这一点很重要,因为一次只允许一个 Activity 拥有对摄像头的访问权限,并且如果您的 Activity 在它终止之前从未释放它,那么您的摄像头实际上是无用的,直到您重新启动手机。
另外,请务必在您的 CountDownTimer 上致电 .cancel()
// YourActivity.java
@Override
public void onPause(){
super.onPause();
if(superStrobe != null){
superStrobe.cancel();
}
if(camera != null){
camera.release();
camera = null;
}
}
编辑 2
我花了一些时间为您的应用构建了效果,并确保它能够干净利落地处理自己。不错的频闪!因此,您需要牢记以下几点:
相机在处理时需要特别小心,因此您需要谨慎设置和拆卸 Activity。
使用旨在安全处理资源的特定方法对您有很大帮助。尽量不要使用您的相机或计时器,除非您通过在他们尝试操作之前安全地检查他们正在做什么的方法来操作。
一般来说,最好在 .onResume() 中设置 Activity,在 .onPause() 中进行拆卸
我将跳过您似乎已经理解的部分,但为您和其他发现此内容的人指出一些非常重要的注意事项。
因为处理 Android 摄像头有点危险,所以您需要这样的方法,并且它们应该成对出现。一个用于创建您的资产,另一个用于清理它们:
// Ways to safely access the camera...
safelyAcquireCamera()
safelyReleaseCamera()
// Ways to safely access the timer...
startTimer()
stopTimer()
// Ways to setup your button...
setupButton()
// Special error handling code that makes sure to clean up the Activity if it crashes.
setupUncaughtExceptionHandler()
restoreOriginalUncaughtExceptionHandler()
你会想要这样的变量
Camera camera;
Camera.Parameters cameraParameters;
CountDownTimer countDownTimer;
UncaughtExceptionHandler originalExceptionHandler;
boolean timerIsStarted = false;
我会为你分解这个。这可能看起来相当长,但这里有很多概念:
@Override
public void onResume() {
super.onResume();
this.setupUncaughtExceptionHandler();
// ^^ Super important! ^^
// This saves you if you crash!
boolean didAcquireCamera = safelyAcquireCamera();
setupButton(didAcquireCamera);
// ^^ Set up your button, letting the
// method know if you succeeded in acquiring the camera.
// you probably know how to implement this already.
}
@Override
public void onPause() {
super.onPause();
stopTimer();
// FIRST stop your timer. Even though the timer has logic that
// accounts for you doing this out of order, it's still correct
// to stop your running action first.
safelyReleaseCamera();
// Now you should release your camera using your safe method.
releaseButtons();
// Release your buttons...
restoreOriginalUncaughtExceptionHandler();
// ^^ Since you safely cleaned up your Activity
// it is s time to restore the Exception Handler.
}
protected void stopTimer() {
// This method gives you a safe way to stop the timer.
if (countDownTimer != null) {
countDownTimer.cancel();
countDownTimer = null;
timerIsStarted = false;
}
}
protected void safelyReleaseCamera() {
// This method gives you a safe way to release the camera.
if (camera != null) {
// You probably want to make sure to turn the flash off
// if you had it on already!
if (cameraParameters != null) {
cameraParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(cameraParameters);
camera.stopPreview();
}
camera.release();
camera = null;
cameraParameters = null;
}
}
protected boolean safelyAcquireCamera() {
safelyReleaseCamera();
// ^^ It's very important to make sure your app DOES NOT
// have a stray camera before you try to acquire a new one!
// Be absolutely sure to call safe release before you try to
// call Camera.open(); here.
/**
* You seem to know how to acquire the camera already. Just
* return true if you succeeded and false if you didn't.
**/
return camera != null;
}
protected void startTimer(long millisInTheFuture, long countDownInterval) {
stopTimer();
timerIsStarted = true;
countDownTimer = new CountDownTimer(millisInTheFuture, countDownInterval) {
@Override
public void onTick(long millisUntilFinished) {
if (camera == null || cameraParameters == null) {
stopTimer();
return;
// Clearly things have gone awry if you lost your camera!
// Bail Out.
}
/**
* Do your strobing like normal in here...
**/
}
@Override
public void onFinish() {
timerIsStarted = false;
}
};
countDownTimer.start();
}
protected void setupButtons(boolean didAcquireCamera){
/**
* You seem to have a good handle on
* how to set up a button. Make it so!
**/
}
protected void releaseButtons(){
// And here you should safely set all your button handlers to null!
}
/*****************
* Safety Methods
* This might be advanced, but I'll try to make it simple.
*****************/
private void setupUncaughtExceptionHandler() {
restoreOriginalUncaughtExceptionHandler();
// ^^ Ensure that you're in as close to a default state as you can.
Thread currentlyRunningThread = Thread.currentThread();
originalExceptionHandler = currentlyRunningThread.getUncaughtExceptionHandler();
// ^^ This is the thing that happens when your app normally crashes.
// You'll be giving it a new, special set of instructions in this case,
// but you'll still want to hold onto the default implmenetation.
currentlyRunningThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
stopTimer();
safelyReleaseCamera();
// ^^ You don't know how or why you crashed.
// So call your safe disposal methods here!
releaseButtons();
if(originalExceptionHandler != null){
originalExceptionHandler.uncaughtException(thread, ex);
// Now make sure you call the original handler so that
// Android does its normal crash thing.
}
thread.setUncaughtExceptionHandler(originalExceptionHandler);
// And restore the original crash behavior to be the default.
}
});
}
private void restoreOriginalUncaughtExceptionHandler() {
if (originalExceptionHandler != null) {
Thread.currentThread().setUncaughtExceptionHandler(originalExceptionHandler);
originalExceptionHandler = null;
}
}
您可能需要滚动上面的代码区域。
希望这对不同经验水平的人有所帮助。其中一些可能看起来像黑魔法,但我已尽力解释其背后的原因。