I am creating a simple Morse code app. The user can enter in text which is then translated to Morse and flashed in sequence on a new thread. I have implemented a for loop which is used to turn on/off the camera flash to represent the Morse sequence.
The problem is that when the user navigates away from the activity the on pause method releases the camera but i sometimes get the error 'method called after release'. I am not sure how to cancel the thread from running when the camera is released. I have already attempted to use a volatile Boolean value which is checked at the start of each loop iteration but if the loop is cancelled at any other time but the start then it results in an error.
Does anyone have any ideas/suggestions as to how i could solve this problem?
public void flashTranslation(String message) {
int offIntervalTime = 50;
char[] cArray = message.toCharArray();
for (int i = 0; i < cArray.length; i++) {
if (cArray[i] == '.') {
turnOn();
try {
Thread.sleep(50);
}catch(Exception e)
{
Log.d("One", "Two");
}
turnOff();
try {
Thread.sleep(offIntervalTime);
}catch(Exception e)
{
}
} else if(cArray[i] == ' ')
{
Log.d("EMPTY!", "EMPTY!");
try{
Thread.sleep(100);
}catch(Exception e)
{
}
}
else {
try{
turnOn();
Thread.sleep(dash);
}catch(Exception e)
{
}
try{
turnOff();
Thread.sleep(offIntervalTime);
}catch(Exception e)
{
}
}
}
}
The easiest way to do this is canceling the thread protecting against concurrent access via semaphore. Every time you try to flash on the thread, you check if the thread is canceled. Pseudocode:
Semaphore sem;
onPause(){
sem.take();
camera.turnOff();
camera.release();
thread.cancel();
sem.give();
}
thread.run() {
//This should be run before every call to turnOn or turnoff
sem.take();
if(isCanceled()) {
return;
}
turnOn();
sem.give();
}
onResume() {
new Thread.start();
}
Related
I am in the process of making a simple practice Morse code application.
I am trying to make an Image View flash between black and white in the SOS sequence based on Morse. When researching how to achieve this i realized i would have to do this on a separate thread in order to not block the UI thread.
The problem is that i am currently updating the Image View from outside of the UI thread which is stated to be a bad idea. At the moment i am trying to pass the Image View to the worker thread class that contains the logic for the screen flash.
I am new to multi-threading and i am pretty sure i am doing this completely backwards/incorrectly. Does anyone have an advice or ideas as of the best method to go about this?
new Thread(new Runnable() {
public void run() {
sf = new ScreenFlash("...---...", imgV);
sf.flashScreen();
}
}).start();
public ScreenFlash(String message, ImageView imgV){
this.message = message.replaceAll(".(?!$)", "$0 ");
this.imgV = imgV;
}
public void flashScreen() {
int offIntervalTime = 50;
char[] cArray = message.toCharArray();
for (int i = 0; i < cArray.length; i++) {
if (cArray[i] == '.') {
imgV.setBackgroundColor(Color.WHITE);
try {
Thread.sleep(50);
}catch(Exception e)
{
}
imgV.setBackgroundColor(Color.BLACK);
try {
Thread.sleep(offIntervalTime);
}catch(Exception e)
{
}
} else if(cArray[i] == ' ')
{
try{
Thread.sleep(100);
}catch(Exception e)
{
}
}
else {
try{
imgV.setBackgroundColor(Color.WHITE);
Thread.sleep(dash);
}catch(Exception e)
{
}
try{
imgV.setBackgroundColor(Color.BLACK);
Thread.sleep(offIntervalTime);
}catch(Exception e)
{
}
}
}
Take a look at the Handler class documentation and how to communicate with the UI thread from a background thread:
http://developer.android.com/training/multiple-threads/communicate-ui.html
You can update your imageView in onHandleMessage()
#Override
public void handleMessage(Message inputMessage) {
imageView.setBackgroundColor(android.R.color.white)
...
}
When another thread calls closeConnection(), the thread doesn't reach
Log.d("Subscriber", "Client thread has ended.");
Why is this? What is the blocking behaviour of a stream that has been closed? I thought trying to write or flush to it would generate an IOException, but it seems the code is still blocking somewhere. Where? I can't find info on what happens when you interrupt() on a write, or what happens when writing to a closed outputstream.
public void closeConnection() {
try {
this.interrupt();
autoCloseOutputStream.close();
} catch (IOException e) {
Log.w("Subscriber", "IOException when closing stream. Buffer might not have been flushed to client.");
}
}
#Override
public void run() {
Log.d("Subscriber","Client thread has started.");
ByteBuffer pgnAndDataBytes=null;
while(true) {
try {
pgnAndDataBytes=fmsByteBufferSubscriberQueue.take();
} catch (InterruptedException e) {
break;
}
Log.d("Subscriber","Still running thread");
try {
autoCloseOutputStream.write(pgnAndDataBytes.array());
autoCloseOutputStream.flush();
} catch (IOException e) {
break;
}
}
Log.d("Subscriber", "Client thread has ended.");
}
The output is as follows:
Still running thread
Still running thread
Still running thread
Close called.
And nothing more. Where is it blocking and why?
Have a volatile boolean shouldClose that you set to true on closeConnect(). Incorporate the boolean into the condition check of the while loop.
boolean done = false;
while(!shouldClose && !done) {
try{
autoCloseOutputStream.write(pgnAndDataBytes.getInt());
} catch(BufferUnderflowException bue) {
final ArrayList<Byte> remainder = new ArrayList<Byte>(3);
while(!shouldClose && !done) {
try {
remainder.add(pgnAndDataBytes.get());
} catch(BufferUnderflowException ex) {
autoCloseOutputStream.write(remainder.toArray(new Byte[remainder.size()]);
done = true;
}
}
}
}
Maybe the code kind of shows what I'm attempting to do, so I'll start with that
private void getLicenseResults() {
if (licensed && didCheck == true) {
Thread timer = new Thread() {
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
Intent openStartingPoint = new Intent(
"***.MAINACTIVITY");
startActivity(openStartingPoint);
finish();
}
}
};
timer.start();
}
if (didCheck == false) {
Toast.makeText(Splash.this, "Checking License, Please Wait",
Toast.LENGTH_LONG).show();
Thread timer = new Thread() {
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
getLicenseResults();
Log.i("LICENSE", "re-checking");
}
}
};
timer.start();
}
}
I ran the license check without trying to loop it before, and it worked except if the checking took more than a couple seconds it skipped over the
if (licensed && didCheck == true)
and the activity just kind of stood and waited without launching my main activity (this check is on the splash screen).
So I want the "if didCheck = true" part to be called only after didCheck is in fact finally true. I'm sure there's an easy solution, but I'm self-taught and I have no experience with loops or callbacks(?).
Thank you for any help!
You are not setting didCheck to true in your second if statement before the call to getLicenseResults
Hi,
In my app im trying to use Thread.sleep(100) to pause my thread, while its backgrounded in order to use less cpu, but it freezes when I open it back up.
I realized that onResume is not being called when I reopen the app.
Any ideas why?
public void onPause() {
pause = true;
Log.d("mSTATE","THREADPAUSE");
}
public void onResume() {
pause = false;
running = true;
Log.d("mSTATE","THREADRESUME");
}
public void run() {
while(running){
while(pause && running){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (!pause && running) {
Canvas c = null;
try {
c = sHolder.lockCanvas(null);
synchronized (sHolder) {
doDraw(c);
powerUps();
}
} finally {
if (c != null) {
sHolder.unlockCanvasAndPost(c);
}
}
}
}
Log.d("mState","EndofRun");
}
When you put your thread to sleep you are also blocking the UI thread thus leading to freezing of your application.
You need to check the Threads in Android way for the best performance.
http://developer.android.com/resources/articles/painless-threading.html
Wanted to stop a thread doing some downloads.
The code below work fine when i only have the stopNow = true; and no blocking occur.
I create the boolean stopNow = false; as a field in my IntentService.
Since stopNow only work when the connection is ongoing in the while loop
but it does not work if f.ex connection stales and start to block.
I wanted to add this code to really stop the blocking.
if(socket != null){
socket.shutdownOutput();
socket.shutdownInput();
}
The question is if this is asynchronous so if the execution is ongoing in the
while loop the stopNow = true; will stop it and i can put a sleep(5000) after the stopNow = true; and then the if(socket != null) will be true only if the stopNow had no effect.
hope you follow me..
BroadcastReceiver that are located inside the run():
private class MyIncomingListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Consts.COM_CARLSBERG_STOPOUTGOING)) {
String b = intent.getStringExtra(Consts.COM_CARLSBERG_BATCHUUID);
if(b != null){
if(b.equals(batch.batchUuid)){
stopNow = true;
// sleep(5000) wait for stopNow to take effect
// if socket=null then stopNow did it's job
// if socket is alive then there is blocking to unblock
try{
if(socket != null){
socket.shutdownOutput();
socket.shutdownInput();
}
} catch (Exception e) {}
}
}
}
}
}
this is actually working good so far
stopNow = true;
try{
if(socket != null){
socket.shutdownOutput();
socket.shutdownInput();
}
} catch (Exception e) {}
public final void stop ()
Since: API Level 1
This method is deprecated.
because stopping a thread in this manner is unsafe and can leave your application and the VM in an unpredictable state.
Requests the receiver Thread to stop and throw ThreadDeath. The Thread is resumed if it was suspended and awakened if it was sleeping, so that it can proceed to throw ThreadDeath.
try {
int waited = 0;
while(_active && (waited < _splashTime)) {
sleep(100);
if(_active) {
waited += 100;
}
}
} catch(InterruptedException e) {
// do nothing
} finally {
finish();
Intent intent= new Intent(SplashActivity.this,LoginViewController.class);
startActivity(intent);
stop();
}