问题
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().
回答1:
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);
回答2:
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();
}
};
来源:https://stackoverflow.com/questions/18185384/blinking-flash-according-to-morse-code-android-how-to-avoid-anrs-due-to-sleepi