Android App crashes after backpress with Handler and Camera
I am trying to use camera for an SOS app , the code runs when we start the sos flash using the button click in order to keep the flash light running , I am using Handler with Post delay
the app crashes when we use backpress to go back to the previous activity
I have tried using handler.removeCallbacks(r); , onbackpress but still the app crashes
this is the code I am trying
public class sos extends Activity {
String myMorseString = "111000111";
int sleepTime;
Camera cam;
Handler handler;
Runnable r;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sos);
ImageButton button = (ImageButton) findViewById(R.id.Start);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startsos();
}
});
}
public void startsos() {
// new Thread() {
handler = new Handler();
r = new Runnable() {
public void run() {
if (myMorseString != null) {
for (int x = 0; x < myMorseString.length(); x++) {
if (myMorseString.charAt(x) == '2') {
cam = Camera.open();
sleepTime = 500;
Parameters p = cam.getParameters();
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
cam.startPreview();
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
// power off after signal
cam.stopPreview();
cam.release();
cam = null;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
if (myMorseString.charAt(x) == '1') {
cam = Camera.open();
sleepTime = 250;
Parameters p = cam.getParameters();
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
cam.startPreview();
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// power off after signal
cam.stopPreview();
cam.release();
cam = null;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (myMorseString.charAt(x) == '0') {
cam = Camera.open();
sleepTime = 250;
Parameters p = cam.getParameters();
cam.setParameters(p);
//cam.startPreview();
cam.stopPreview();
cam.release();
cam = null;
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
handler.postDelayed(this, 10000);
}
// }.start();
};
handler.postDelayed(r, 10000);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onBackPressed() {
handler.removeCallbacks(r);
finish();
super.onBackPressed();
}
}
It's most likely crashing because the camera preview isn't being stopped when back is pressed. The Runnable is just being removed from the Handler.
That being said, you're also going to see another problem: creating a Handler from within an onClick() handler isn't creating a new thread. It's still creating a Handler which is bound to your main thread. The onClick() (and any view related callback) is called on the main (UI) thread. So the sleep() calls you are making in the Runnable are happening on your main thread, which is very bad.
Related
if(!isOn) {
imageButton.setImageResource(R.drawable.on);
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
camera.startPreview();
isOn = true;
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
I wanna add a timer to the flashlight app such that it keeps the flashlight on for the selected time
This is the code which works for me.
public void NotifyWithFlash(Context context){
boolean ShouldIGlow = true;
while(ShouldIGlow){
flashON();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
ShouldIGlow = false;
flashOFF();
}
}
}
public void flashON(){
Camera cam = Camera.open();
Parameters p = cam.getParameters();
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
cam.startPreview();
}
public void flashOFF(){
cam.stopPreview();
cam.release();
}
I wanna add a timer to the flashlight app such that it keeps the flashlight on for the selected time so just set timer using Thread whatever you want as Thread.sleep(user decided period); for example Thread.sleep(5000);
You shouldn't use Thread.sleep() because it will block the UI. Instead you have android.os.Handler :
flashOn();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
flashOff();
}
}, 5000); // 5000 ms = 5 sec
there Folks! And Here it goes another Question.. from me..
I'm making a flashlight app. In the app there are two buttons, one is for turning on/off flash (flashlight_switch) and the other one is for blinking the flash With a single tap on the Button (sos_switch) at medium speed. The flash on/off works perfectly, but when i press the SOS button the app freezes and crashes. And also how can I turn off the SOS. I'm a beginner so it would be very nice that you explain the answer in depth. Please ignore Any typos if there are. The App is tested on Galaxy S3 and LG G3 and no luck on both of them.
Here is the complete code:
Java:
FlashlightActivity:
public class FlashlightActivity extends Activity {
ImageButton flashlight_switch;
ImageButton sos_switch;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flashlight);
flashlight_switch = (ImageButton) findViewById(R.id.flashlight_switch);
sos_switch = (ImageButton) findViewById(R.id.sos_switch);
flashlight_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if (Flash.getTorch()) {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_on);
} else {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_off);
}
}
});
sos_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (SOS.getSOS()) {
sos_switch.setImageResource(R.drawable.sos_on);
} else {
sos_switch.setImageResource(R.drawable.sos_off);
}
}
});
}
}
Flash:
class Flash {
private static boolean flashOnOff = false;
private static boolean sosOnOff = false;
public static Camera camera;
private static Camera.Parameters params;
public static boolean getTorch() {
if (flashOnOff)
off();
else
on();
return flashOnOff;
}
public static boolean getSOS() {
if (sosOnOff)
offSOS();
else
onSOS();
return sosOnOff;
}
private static void on() {
if (!flashOnOff) {
if (camera == null || params == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
int a = 10;
}
}
try {
camera.setPreviewTexture(new SurfaceTexture(0));
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
flashOnOff = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void off() {
if (camera == null || params == null)
return;
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
camera.release();
camera = null;
flashOnOff = false;
}
private static void onSOS() {
Thread t = new Thread() {
public void run() {
try {
int delay = 50;
int times = 10;
for (int i=0; i < times*2; i++) {
if (flashOnOff) {
on();
} else {
off();
}
sleep(delay);
}
} catch (Exception e){
e.printStackTrace();
}
}
};
t.start();
}
private static void offSOS() {
Thread t = new Thread();
t.stop();}}
Thanks In Advance!
Update:
I have updated my flash.java. It does not crash now but still the SOS don't work and also the sos switch freezes. I can't figure it out now. Please help!!!! as soon as possible!
You should not sleep Thread.sleep(blinkDelay); the thread because it is main thread need to update UI.you should use a different thread for SOS on
And Your SOS on function is in recursive infinite loop plz edit it. You are calling ON infinite time recursivly
Make Flash class ON / OFF method to public and make few changes in SOS's on method on(); to Flash.on and off to Flash .off
Flash.java
class Flash {
private static boolean flashOnOff = false;
public static Camera camera;
private static Camera.Parameters params;
static Thread t;
public static boolean getTorch() {
if (flashOnOff) // turn off flash
off();
else // turn on flash
on();
return flashOnOff;
}
private static void on() {
if (!flashOnOff) {
if (camera == null || params == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
int a = 10;
}
}
try {
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.setPreviewTexture(new SurfaceTexture(0));
camera.startPreview();
flashOnOff = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void off() {
if (camera == null || params == null)
return;
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
flashOnOff = false;
}
public static void onSOS() {
t = new Thread() {
public void run() {
try {
int delay = 50;
while (true) {
if (t.isInterrupted())
break;
getTorch();
sleep(delay);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
}
public static void offSOS() {
if (!t.isInterrupted()) {
t.interrupt();
off();
}
}}
FlashlightActivity.java
public class FlashlightActivity extends Activity {
ImageButton flashlight_switch;
ImageButton sos_switch;
boolean isStart = false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flashlight);
flashlight_switch = (ImageButton) findViewById(R.id.flashlight_switch);
sos_switch = (ImageButton) findViewById(R.id.sos_switch);
flashlight_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if (Flash.getTorch()) {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_on);
} else {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_off);
}
}
});
sos_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isStart){
Flash.onSOS();
isStart = true;
sos_switch.setImageResource(R.drawable.sos_off);
}else{
Flash.offSOS();
isStart = false;
sos_switch.setImageResource(R.drawable.sos_on);
}
}
});
}
}
I have created a thread in a class, The code is as follows
private void startThread() {
if (t != null) {
t.interrupt();
}
isFlashOn = true;
t = new Thread() {
public void run() {
try {
try {
SurfaceView surfaceView = (SurfaceView) activity
.findViewById(R.id.surfaceViewCam);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
// surfaceHolder.addCallback(this);
camera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
e.printStackTrace();
}
camera.startPreview();
for (int i = seekBarManager.preferenceManager
.get_duration(); i > 0 && !this.isInterrupted(); i--) {
isFlashOn = true;
setBlinkToggle();
sleep(seekBarManager.preferenceManager.get_delay());
if(isFlashOn==false){
break;
}
}
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
}
I stop the thread in a method
private void stopThread() {
if (t != null) {
t.interrupt();
//t.
isFlashOn = false;
}
}
The problem I am facing is, The for loop in the thread seems to be running even after the successful call of Interrupt()
Any help here would be greatly appreciated!
Updated Code
t = new Thread() {
public void run() {
Boolean isStop = false;
try {
try {
SurfaceView surfaceView = (SurfaceView) activity
.findViewById(R.id.surfaceViewCam);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
// surfaceHolder.addCallback(this);
camera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
e.printStackTrace();
}
camera.startPreview();
for (int i = seekBarManager.preferenceManager
.get_duration(); i > 0 && !isStop; i--) {
isFlashOn = true;
setBlinkToggle();
sleep(seekBarManager.preferenceManager.get_delay());
}
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
}
} catch (Exception e) {
e.printStackTrace();
isStop=true;
//notify();
return;
}
}
};
Purpose of interrupt():
It just sets the interrupted flag to true. After interrupt() has been called the Thread.currentThread().isInterrupted() starts to return false. And that's all.
Another case is if interrupt() is called while the thread is blocked in an invocation of one of the methods that throw InterruptedException, then that method will return throwing the InterruptedException. And if thread's code just "eats" that exception, then the thread will still continue running.
So the correct approach should be to periodically check the interrupted flag. And if interrupted status is detected then just return ASAP. Another common option is not to use Thread.interrupt() at all, but some custom boolean instead.
See the below link for safe stop of thread:-
http://www.java2s.com/Code/Java/Threads/Thesafewaytostopathread.htm
So, I made a torch app... The normal Torch function is fully working, no problems.
The following explains the below function that can cause possible ANRs
Say, I want to send out an SOS message (morse code) through the blinking flash.
(its 111-000-111)
So it's On-On-On-Off-Off-Off- and repeat.
(Read Slowly)
I "On" it for a little while, then a little flash, "On" again - This is to distinguish two consecutive "On"s ... That's how I get three distinct flashes.
Trouble is, for Time delay, I put the thread to sleep.(This method has worked the best for me)
Here's my sample function , it flashes out SOS:
(I have a seperate button for SOS)
public void sos(View v) {
String myString = "111000111";
for (int x = 0; x < myString.length(); x++) {
if (myString.charAt(x) == '1') {
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
c.setParameters(p);
c.startPreview();
flag = true;
} else {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(p);
flag = false;
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(p);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(p);
}
}
The above flashes out SOS just once.
But while this flashing and blinking is going on , my app is frozen up. The Blinking SOS is perfect. But it doesn't respond to any button clicks or even Back Button to stop it midway.
I reckon this is because the thread(UI) is sleeping hence it doesn't care about what the user is doing)... But the click surely is registered, and if according to android if it isn't looked after in the stipulated period of time (I think a few seconds) ... The app goes ANR.
So, I need brief pauses with intervals defined by me (As above I use 300 milliseconds). But I also want to know how to get the app to simultaneously respond to say Button Clicks, or Back Button Presses so as to avoid ANR's and give the user the ability to shut down the blinking at any time.
How to do this ?
EDIT
Waza_Be's Solution:
Okay so here's my modified function according to Waza_Be. The problem seems to be, it does wait 300 milliseconds(in my case) ...But I have several postDelay functions - So I think it's actually lining up all the functions together, and the waiting period of the 300 milliseconds is somewhat overlapping. After this period ends, all the code runs together at once, making it quite pointless.
When I tried this, the Flash blinks rather swiftly, not with the subtle pauses and blinking effect I want.
public void sos(View v) {
String myString = "111000111";
Handler handler = new Handler();
for (int x = 0; x < myString.length(); x++) {
if (myString.charAt(x) == '1') {
handler.postDelayed(new Runnable() {
public void run() {
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
c.setParameters(p);
c.startPreview();
}
}, 300);
} else {
handler.postDelayed(new Runnable() {
public void run() {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(p);
}
}, 300);
}
handler.postDelayed(new Runnable() {
public void run() {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(p);
}
}, 300);
}
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(p);
}
}
I need separate pauses. Say after or before every TURN_ON or TURN_OFF for the Flash.
In each loop, it should wait individually for each piece of code in the Handler Run().
I personally use Handler postDelayed when I want to "sleep"
// "SLEEP" 2 SECONDS HERE ...
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); // Or watherver you want
c.setParameters(p);
}
}, 2000);
You could also use the sleep method in a thread to avoid blocking the UI thread.
Edit:
This is how you can write a recursive handler:
This will allow you to send all the Morse part on after the other
Handler handler = new Handler();
int i = 0;
Runnable myRunnable = new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
if(i>5)
handler.removeCallback(myRunnable);
else{
i++;
handler.postDelayed(myRunnable, 100); // here is self calling
}
}
};
}
handler.postDelayed(myRunnable, 100);
I solved this a little different using Thread.
The morse code is generated by clicking a button.
OnClickListener goMorse = new OnClickListener() {
#Override
public void onClick(View v) {
new Thread () {
public void run() {
if(myMorseString != null){
for (int x = 0; x < myMorseString.length(); x++) {
if (myMorseString.charAt(x) == '2') {
cam = Camera.open();
sleepTime = 500;
Parameters p = cam.getParameters();
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
cam.startPreview();
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// power off after signal
cam.stopPreview();
cam.release();
cam = null;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (myMorseString.charAt(x) == '1') {
cam = Camera.open();
sleepTime = 250;
Parameters p = cam.getParameters();
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
cam.startPreview();
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// power off after signal
cam.stopPreview();
cam.release();
cam = null;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (myMorseString.charAt(x) == '0') {
cam = Camera.open();
sleepTime = 250;
Parameters p = cam.getParameters();
cam.setParameters(p);
//cam.startPreview();
cam.stopPreview();
cam.release();
cam = null;
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}}}
}.start();
}
};
I am using a thread to run the flashlight and I want to stop that thread after the back is pressed.
I used the following code to start the thread:
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Flashing...");
progressDialog.show();
thread = new Thread(MainActivity.this);
thread.start();
And the thread is doing:
public void run() {
isOn = false;
cam = Camera.open();
p = cam.getParameters();
try {
for (int i = 0; i < pattern.length; i++) {
if (isOn) {
p.setFlashMode(Parameters.FLASH_MODE_OFF);
cam.setParameters(p);
Thread.sleep(pattern[i]);
isOn = false;
} else {
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
Thread.sleep(pattern[i]);
isOn = true;
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
cam.release();
handlerFinish.sendEmptyMessage(0);
}
private Handler handlerFinish = new Handler() {
#Override
public void handleMessage(Message msg) {
progressDialog.dismiss();
}
};
I have tried this to stop, but there are only the progress dialog is dismissed but the flashlight is still working:
#Override
public void onBackPressed() {
super.onBackPressed();
p.setFlashMode(Parameters.FLASH_MODE_OFF);
cam.setParameters(p);
isOn = false;
thread.stop();
}
What can I do to achieve my goal (Stop the thread and flashlight after back is pressed)?
try this loop to stop the thread
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}