我在Google上有几个应用程序。
在这些应用程序中,我有一个闪光灯,当用户按下按钮时会运行。 问题是,当我切换活动时,应用程序崩溃了。由于在用户按下时相机的参数设置为开,我得到了一些帮助。这意味着当他们进入下一个要求摄像头的活动时,应用程序会崩溃。我甚至在手机上下载了应用程序,有时手机也停止响应。我试图弄清楚为什么我自己的手机开始行动,我发现我的应用程序导致了这些问题。
这是我的宝贝!我试图弄清楚如何制作这个特定的实现,我们两个星期的时间。
public void strobeTimer182() {
superStrobe = new CountDownTimer(857, 1) {
public void onTick(long millisUntilFinished) {
if (millisUntilFinished % 2 == 0) {
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(p);
camera.startPreview();
p.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(p);
camera.stopPreview();
} else {
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(p);
camera.startPreview();
p.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(p);
camera.stopPreview();
crazy.nextInt(265)));
}
if (millisUntilFinished == 0) {
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(p);
camera.startPreview();
p.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(p);
camera.stopPreview();
}
}
我已经读过它了,因为当手机预计它们关闭时,相机的参数会打开。
我的问题是。为什么会这样呢?您可以在代码中看到if语句应该完全转换它。
这里是一些关于错误的代码。
这是我的onStart()
@Override
protected void onStart() {
super.onStart();
// on starting the app get the camera params
getCamera();
// turnOffFlash();
}
和getCamera()"按钮"是按钮上的切换摄像头。所以当应用程序启动时......你必须打开它。有些手机不能正常使用相机,所以我想我必须首先检查..当你按下其他按钮时......音乐播放和频闪播放857毫秒......你可以看到。
public void getCamera(){
Context context = this;
// Retrieve application packages that are currently installed
// on the device which includes camera, GPS etc.
PackageManager pm = context.getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Log.e("err", "Device has no camera!"); // Toast a message to let the
// user know that camera is not // installed in the device
Toast.makeText(getApplicationContext(),
"Your device doesn't have camera!", Toast.LENGTH_SHORT)
.show();
button.setEnabled(false);
// Return from the method, do nothing after this code block
return;
} else {
camera = Camera.open();
p = camera.getParameters();
}
}
答案 0 :(得分:3)
您需要确保在活动暂停或暂停时释放相机。这很重要,因为一次只允许一项活动拥有对摄像机的访问权限,如果您的活动在死亡之前从未释放,那么在您重新启动手机之前,您的摄像机实际上是无用的。
另外,请务必在CountDownTimer上调用.cancel()
// YourActivity.java
@Override
public void onPause(){
super.onPause();
if(superStrobe != null){
superStrobe.cancel();
}
if(camera != null){
camera.release();
camera = null;
}
}
编辑2
我花了一些时间来构建你的应用程序的效果,并确保它干净利落地处理。好闪光!所以,这里有一些你真正需要记住的事情:
相机需要特别小心处理,因此您需要对如何设置和拆除活动一丝不苟。
使用旨在安全处理资源的特定方法对您有很大帮助。尝试永远不要处理你的相机或你的计时器,除非你通过方法安全地检查他们在做什么之前做了什么。
一般情况下,最好在.onResume()
进行活动设置,并在.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;
}
}
您可能需要滚动上面的代码区域。
希望这对各种经验水平的人都有帮助。其中一些可能看起来像黑魔法,但我已尽力解释背后的为什么。