I have a thread created inside a secondary activity on Android, like so:
new Thread(new Runnable() {
public void run() {
try {
String branch=spinner.getSelectedItem().toString();
while( branch.equals(spinner.getSelectedItem().toString())){
System.out.println("----LOOPER."+spinner.getSelectedItem().toString());
GetQinfo a= (GetQinfo) new GetQinfo().execute(city,type,org,spinner.getSelectedItem().toString());
Thread.sleep(refreshRate);
}
} catch (InterruptedException e){
e.printStackTrace();
}
return;
}
}).start();
the problem is that when i go back to the main activity this thread is still running.
what i did was on the goback button to write this:
spinner.setSelection(0);
this.finish();
This way the value of the spinner is changed, causing the while loop on the thread to return false, thus exiting the thread.
But i dont think this is the right way of doing it. can anyone suggest something different, or should i say, better
You should use interrupt() method of the thread when you leave the activity.
YourThread.interrupt();
new Thread(new Runnable() {
public void run() {
try {
if(!Thread.interrupted())
String branch=spinner.getSelectedItem().toString();
while( branch.equals(spinner.getSelectedItem().toString())){
System.out.println("----LOOPER."+spinner.getSelectedItem().toString());
GetQinfo a= (GetQinfo) new GetQinfo().execute(city,type,org,spinner.getSelectedItem().toString());
Thread.sleep(refreshRate);
}
} catch (InterruptedException e){
e.printStackTrace();
}
return;
}
}).start();
There is no method explicitly available to stop a thread. There were methods previously to stop the thread but they were deprecated. Please read the following link to see why the developers of java wanted it this way: http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
According to this document, they prefer that you do it in the manner that you suggested. So you're not wrong.
private volatile boolean stopThread;
public void run() {
String branch=spinner.getSelectedItem().toString();
while (!stopThread) {
System.out.println("----LOOPER."+spinner.getSelectedItem().toString());
GetQinfo a= (GetQinfo) new GetQinfo().execute(city,type,org,spinner.getSelectedItem().toString());
Thread.sleep(refreshRate);
}
}
public void stopThread() {
stopThread = true;
thread.interrupt();
}
Related
I have a worker thread that is running in the background. On this worker thread, I have a method called syncWithUiThreadAndWait. Here is the simplified code:
private void syncWithUiThreadAndWait(final Runnable codeToSync) {
if (looper == null)
throw new RuntimeException("Thread is not ready (Looper=null)");
if (looper != Looper.myLooper())
throw new RuntimeException("Called from wrong thread");
final boolean[] wasRun = {false};
new Handler(looper).post(new Runnable() {
// I use 'new Handler(looper).post' instead of direct call to make sure that this code will
// run 100% after Looper.loop() is called, because in some cases it can be called before Looper.loop
#Override
public void run() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
synchronized (MyWorkerThread.this) {
// Synchronization to establishes a happens-before relationship
wasRun[0] = true;
looper.quit();
}
}
});
}
});
Looper.loop();
synchronized (MyWorkerThread.this) {
// Synchronization to establishes a happens-before relationship
if (!wasRun[0])
throw new RuntimeException("WHY!!!");
}
}
So my question is: why sometimes this code runs correctly and sometimes thread loop does not start and I receive my 'WHY' exception?
Edit:
I decided to add some explanation to make it easier to understand.
What I am trying to do is a synchronized thread with UI thread.
First, prepare task new Handler (looper) .post (...); that will be run once I 'block' my background thread from continuing.
After that, I 'block' my background thread by Looper.loop ();
The task that I prepared will run once the loop is looped and will fire code for UI thread.
Lastly, at the end of the code that will be run on UI thread looper.quit (); is called to unblock background thread.
So even though I still don't know why it was happening. So if someone can explain I will mark it as a correct answer.
But I found a workaround using Thread.sleep() instead of using Looper.loop(). Wich works for me and probably is more efficient:
private void syncWithUiThreadAndWait(final Runnable codeToSync) {
synchronized (this) {
if (thread == null)
throw new RuntimeException("Thread not ready");
if (Thread.currentThread() != thread)
throw new RuntimeException("Called from wrong thread");
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
codeToSync.run();
setPaused(false);
}
});
setPaused(true);
final long sleepStart = System.currentTimeMillis();
while (isPaused()) {
try {
Thread.sleep(200);
} catch (InterruptedException ignored) { }
if (sleepStart + TIMEOUT_IN_MILLISEC <= System.currentTimeMillis())
throw new RuntimeException("Timeout waiting for network response");
}
}
private synchronized boolean isPaused() {
return paused;
}
private synchronized void setPaused(boolean newValue) {
paused = newValue;
}
I have these two methods for creating and stopping a thread. However the thread still keeps running, even after the first method is called. (I'm creating an object of the class and calling them from another class).
private Thread thread;
public void stopAlarm() {
Log.i(LOG_TAG, "stopAlarm called");
sendAlarm = false;
if (!thread.equals(null)) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void triggerAlarm() {
Runnable alarmTest = new Runnable() {
#Override
public void run() {
while (sendAlarm) {
Log.i(LOG_TAG, String.valueOf(sendAlarm));
}
}
};
thread = new Thread(Test);
thread.start();
}
When stopAlarm is called the thread is always null, although it is called after triggerAlarm is called (thread is running).
Your problem is caused by thread scope. Thread scope is created when you create a thread with same variables in the scope but you can't change these variables from outside world. Best practice for managing runnables in android is to use Handler.
Handler handler = new Handler();
Runnable alarmTest = new Runnable() {
#Override
public void run() {
Log.i(LOG_TAG, String.valueOf(sendAlarm));
handler.post(alarmTest, 5000); //wait 5 sec and run again
//you can stop from outside
}
};
after definitions, in order to start the runnable:
handler.post(alarmTest,0); //wait 0 ms and run
in order to stop the runnable:
handler.removeCallbacks(alarmTest);
EDIT: wait statement with loop
EDIT: Complete solution
Handler handler = new Handler();
Runnable alarmTest = new Runnable() {
#Override
public void run() {
Log.i(LOG_TAG, String.valueOf(sendAlarm));
handler.post(alarmTest, 5000); //wait 5 sec and run again
//you can stop from outside
}
};
public void stopAlarm() {
Log.i(LOG_TAG, "stopAlarm called");
handler.removeCallbacks(alarmTest);
}
public void triggerAlarm() {
handler.post(alarmTest,0); //wait 0 ms and run
}
Depending on your OS you may find making your thread volatile may fix this.
private volatile Thread thread;
However - there are better ways to do this. One very useful one is using a small (just one entry) BlockingQueue which is polled by the running thread.
// Use a BlockingQueue to signal the alarm to stop.
BlockingQueue<String> stop = new ArrayBlockingQueue<>(1);
public void stopAlarm() {
stop.add("Stop");
}
public void triggerAlarm() {
new Thread(() -> {
try {
while (stop.poll(1, TimeUnit.SECONDS) == null) {
// Stuff
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
Clearly you will have to manage edge cases like where someone calls stopAlarm when no alarm is running.
How can I run a function synchronously in another thread, meaning the main UI thread has a function that calls another function that does its work on another thread, waits for the new thread to finish and returns the value:
int mainFunction() //this function is on the main UI thread
{
return doWorkOnNewThread();
}
int doWorkOnNewThread()
{
//do work on new thread
}
You can use Async task for this, even though it's asynchronous. You can use the callbacks onPostExecute and onProgressUpdate to update the values as needed. I should also note you probably don't want to do this synchronized as it will block your UI thread which could cause an application not responding alert depending on how long the calculation takes.
There are few ways of executing code in separate threads.
You can read about this here
I think that AsyncTask will do what you want.
protected void onPreExecute () {
// you can show some ProgressDialog indicating to the user that thread is working
}
protected Type doInBackground(String... args) {
doWorkOnNewThread()
// do your stuff here
}
protected void onPostExecute(Type result) {
// here you can notify your activity that thread finished his job and dismiss ProgressDialog
}
You have two way:
1. Asyntask
2. Handler
public static <T> T runSynchronouslyOnBackgroundThread(final Callable<T> callable) {
T result = new Thread() {
T callResult;
#Override
public void run() {
try {
callResult = callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
T startJoinForResult() {
start();
try {
join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return callResult;
}
}.startJoinForResult();
return result;
}
I have a simple Question:
I have a Thread named rlMF. I created it this way:
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles();
stopTh();
}
public void stopTh() {
activityStopped = true;
}
});
Now i want to call the stopTh Function from outer Thread. Why can't i simply call rlMF.stopTh(); and what can i do else?
Example:
protected void onPause() {
Log.d("Info", "destroying...");
activityStopped = true;
rlMF.stopTh();
super.onPause();
}
Is not working...
Because the interface accessible is from Thread. In order to have you method accessible from out, you need to specify a type that exposes this method.
And if you take a look carefully the method is implemented in the instance of Runnable. Not even in Thread.
You could have something like this if you really need to access the Runnable object:
class MyRunnable implements Runnable {
public void run() {
...
}
public void fooBar() {
...
}
}
public void someMethod() {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
...
myRunnable.fooBar();
...
}
An example for Francisco approach, besides what you are trying to achieve. Maybe this can point you in the right direction
public class CustomRun implements Runnable {
public void run() {
reloadMissingFiles();
stopTh();
}
public void stopTh() {
activityStopped = true;
}
}
In your Code
// start thread with custom runner
CustomRun runner = new CustomRun();
new Thread(runner).start();
// call your stopTh method on CustomRun class
protected void onPause() {
Log.d("Info", "destroying...");
activityStopped = true;
runner.stopTh();
super.onPause();
}
Your goal is to interrupt the thread from onPause. There are several ways to do it, but essentially, you will need to include some interruptibility in reloadMissingFiles.
Option 1
You can use a boolean flag like you did - you need to declare it as volatile to make sure the changes are visible across threads:
private volatile boolean activityStopped = false;
public void reloadMissingFiles() {
while (!activityStopped) {
//load small chunks so that the activityStopped flag is checked regularly
}
}
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles(); //will exit soon after activityStopped has been set to false
}
});
protected void onPause() {
//This will stop the thread fairly soon if the while loop in
//reloadMissingFiles is fast enough
activityStopped = true;
super.onPause();
}
Option 2 (better approach)
I don't know what you do in reloadMissingFiles, but I suppose it is some sort of I/O operations, which are generally interruptible. You can then have an interruption policy where you stop as soon as an InterruptedException is caught:
public void reloadMissingFiles() {
try {
//use I/O methods that can be interrupted
} catch (InterruptedException e) {
//cleanup specific stuff (for example undo the operation you started
//if you don't have time to complete it
//then let the finally block clean the mess
} finally {
//cleanup (close the files, database connection or whatever needs to be cleaned
}
}
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles(); //will exit when interrupted
}
});
protected void onPause() {
runner.interrupt(); //sends an interruption signal to the I/O operations
super.onPause();
}
Note: you can also read this article for a more in depth version of it.
Are there any Listeners in Java to handle that some thread have been ended?
Something like this:
Future<String> test = workerPool.submit(new TestCalalble());
test.addActionListener(new ActionListener()
{
public void actionEnd(ActionEvent e)
{
txt1.setText("Button1 clicked");
}
});
I know, that it is impossible to deal like this, but I want to be notified when some thread ended.
Usually I used for this Timer class with checking state of each Future. but it is not pretty way.
Thanks
There is CompletionService you can use.
CompletionService<Result> ecs
= new ExecutorCompletionService<Result>(e);
ecs.submit(new TestCallable());
if (ecs.take().get() != null) {
// on finish
}
Another alternative is to use ListenableFuture from Guava.
Code example:
ListenableFuture future = Futures.makeListenable(test);
future.addListener(new Runnable() {
public void run() {
System.out.println("Operation Complete.");
try {
System.out.println("Result: " + future.get());
} catch (Exception e) {
System.out.println("Error: " + e.message());
}
}
}, exec);
Personally, I like Guava solution better.
No. Such listener does not exist.
But you have 2 solutions.
Add code that notifies you that thread is done in the end of run() method
Use Callable interface that returns result of type Future. You can ask Future what the status is and use blocked method get() to retrieve result
Here is a geekish listener. Highly unadvisible to use but, funny and clever
Thread t = ...
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
#Override
public void uncaughtException(Thread t, Throwable e) {
t.getThreadGroup().uncaughtException(t, e);//this is the default behaviour
}
protected void finalize() throws Throwable{
//cool, we go notified
//handle the notification, but be worried, it's the finalizer thread w/ max priority
}
});
The effect can be achived via PhantomRefernce better
hope you have a little smile :)
Side note: what you ask is NOT thread end, but task completion event and the best is overriding either decorateTask or afterExecute
Without adding a lot of extra code you can make a quick listener thread yourself as follows:
//worker thread for doings
Thread worker = new Thread(new Runnable(){
public void run(){/*work thread stuff here*/}
});
worker.start();
//observer thread for notifications
new Thread(new Runnable(){
public void run(){
try{worker.join();}
catch(Exception e){;}
finally{ /*worker is dead, do notifications.*/}
}).start();
You can implement Observer Pattern to report completion.
public interface IRunComplete {
public void reportCompletion(String message);
}
Let the Thread caller implement this interface.
and in run() method you call this method at the end. So now you exactly knows when this thread gonna end.
Try it. I am actually using this and it's working fine.
You have a join() method defined by Thread class for that. However, you don't have direct visibility to a thread executing your Callable in concurrency API case..
Use this Example:
public class Main {
public static void main(String[] args) {
CompletionListener completedListener = count -> System.out.println("Final Count Value: " + count);
HeavyWorkRunnable job = new HeavyWorkRunnable(completedListener);
Thread otherThread = new Thread(job);
otherThread.start();
}
static class HeavyWorkRunnable implements Runnable {
CompletionListener completionListener;
public HeavyWorkRunnable(CompletionListener completionListener) {
this.completionListener = completionListener;
}
#Override
public void run() {
int count = 0;
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Clock Tick #"+i);
count += 1;
}
if (completionListener != null) {
completionListener.onCompleted(count);
}
}
}
#FunctionalInterface
interface CompletionListener {
void onCompleted(int count);
}
}