I am doing a simple Async operation with Android, but since I want to execute the action couple of times, I am not using AsyncTask, I instead use Thread/Runnable mechanism with Handler to handle messages and staff. But at one point when I need to execute the second operation, I need to cancel the previous operation if it is still active.
I have something like this:
private void exec() {
new Thread(new Runnable() {
public void run() {
mBind.exec(3);
}
}).start();
}
Then in exec(int a) I have an interation like:
for(int i = 0; i<=res.lenght; i++) {
updateGui();
}
But at one point the exec() method is called for second time, and the gui is updated with the previous results too (I need only the results from the new (2nd) request).
I know there is way to do this with FutureTask and play with cancel() or with Thread's 'throw ThreadDead' exception, but I am just curious if I can do it the same way I started in the first place.
thanks!
What I have understand from your question is that you want to cancel the currently running thread if the new thread started.
This you can do by calling Thread's interrupt() method, this will interrupt the currently running thread, and throws the InterruptedException.
Thread t1 = null;
private void exec() {
t1 = new Thread(new Runnable() {
public void run() {
mBind.exec(3);
}
}).start();
}
Before calling exec, call t1.interrupt().
Feels a bit dirty, but could you save the name of the most recently activated Thread and check for it in your Handler? Something like:
private static final int MESSAGE_UPDATE_COMPLETE = 0;
private String threadName;
private void exec() {
Thread thread = new Thread() {
public void run() {
// do stuff
...
Message msg = Message.obtain();
msg.what = MESSAGE_UPDATE_COMPLETE;
msg.obj = this.getName();
handler.sendMessage(msg);
}
};
thread.start();
threadName = thread.getName();
}
...
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case MESSAGE_UPDATE_COMPLETE:
if (threadName.equals((String)msg.obj)) {
// do UI update
}
break;
...
}
}
}
Related
I have the following method, that called every time I click over a button, this results to start a new thread again and again when the button is pressed, that results to multiple initialisation of thread, however I want only one thread should get executed, how can I achieve this.
private void scheduleMessages() {
new Thread(new Runnable() {
#Override
public void run() {
//Some operations
}
}).start();
}
Note: this is a small method and I don't want to create a separate class, just to make it singleton, so a solution without singleton pattern will be appreciated.
if you cannot make instance of this to check isActive() you should make a semaphore variable - a boolean, that you set to true when you start thread and set to false when you are done.
private void scheduleMessages() {
if (!taskRunning){
new Thread(new Runnable() {
#Override
public void run() {
taskRunning = true;
//Some operations
taskRunning = false;
}
}).start();
}
}
Have that thread be a background thread - maybe initialize it when the button is pressed the first time.
Have that thread listen to a queue - and act upon messages in that queue.
Whenever the button is pressed again, put a new message into the queue.
If your need to execute every requests but on a specific number of threads, you can use a thread pool and let the executor manage the queue .
private ExecutorService services;
private final static int POOL_SIZE = 1;
public MessagesService(){
services = Executors.newFixedThreadPool(POOL_SIZE);
}
public void scheduleMessages(Runnable r){
services.submit(r);
}
If you call addCall x times, x thread will be executed at the end but will never use more than the number of thread available in the pool. Here, 1 thread.
For a system that only accept one request, you can use the same approch but check the Future returned by a single thread executor. That way, you can check the status of the service.
private ExecutorService services;
private Future<?> lastCall;
public MessagesService() {
services = Executors.newSingleThreadExecutor();
lastCall = null;
}
public synchronized void scheduleMessages(Runnable r) {
if(!isScheduled()){
lastCall = services.submit(r);
}
}
public boolean isScheduled(){
return lastCall != null && !lastCall.isDone();
}
That way, the Runnable doesn't need to update a flag, which give a reusable solution.
Here is a sample of the Runnable to test these codes :
new Runnable() {
System.out.println("Running");
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
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.
I need to send a message to a HandlerThread from my current thread but stop the sendmessage call from returning immediately. Is there a way to do this sendMessage() in a blocking way?
This is what i think the solution should be.
// This handler will be associated with the UI thread
Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
textView.setText("Progress: " + msg.what);
}
};
private void CreateThread() {
Thread t = new Thread() {
public void run() {
for(int i = 0; i < cnt; i++)
{
try {
Thread.sleep(1000);
} catch (Exception e) {
Log.v("Error: ", e.toString());
}
// You can update the UI by sending messages to the UI thread
uiHandler.sendMessage(uiHandler.obtainMessage(i));
}
}
}
};
t.start();
}
Please take a look at the Exchanger class. I would create an exchanger, send a Runnable having access to that exchanger, and synchronize on that exchanger. This way the exchanger would give me the results obtained asynchronously. You may think out something that would work with messages.
Note that a thread that calls Exchanger.exchange() may have to wait for a long time! (You may get an ANR if you call it from the UI thread.)
It's interesting for me how it's possible to write simple Android Handler class using only pure java to send signals from one thread to another?
I saw the source code:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/os/Handler.java
But how for example to write class (Handler class) that can send for example int value from one thread to another(not using share data(like in Android Handler?))?
If you have the thread in the same method as the handler receiving the message you can do like this:
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do something
}
}
final Thread th = new Thread() {
public void run() {
// do something than send an integer - x in our case
int x = 0;
final Message msg = Message.obtain(handler, x, null);
handler.dispatchMessage(msg);
}
};
th.start();
If your handler can't be accessed directly from the thread than create a class extending Thread and pass the handler to the class's constructor.
This is how you can create your own CustomHandler like android handler by using only Java Api's .
private class CustomHandler {
private final Runnable POISON = new Runnable() {
#Override
public void run() {}
};
private final BlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<>();
public CustomHandler() {
initWorkerThread();
}
private void initWorkerThread() {
new Thread(new Runnable() {
#Override
public void run() {
Log.d("CustomHandler", "worker (looper) thread initialized");
while (true) {
Runnable runnable;
try {
runnable = mQueue.take();
} catch (InterruptedException e) {
return;
}
if (runnable == POISON) {
Log.d("CustomHandler", "poison data detected; stopping working thread");
return;
}
runnable.run();
}
}
}).start();
}
public void stop() {
Log.d("CustomHandler", "injecting poison data into the queue");
mQueue.clear();
mQueue.add(POISON);
}
public void post(Runnable job) {
mQueue.add(job);
}
}
And I would like to point at the question itself that you donot use handler to pass int values from one thread to another. Handlers are use to run tasks in another thread. If you want to share a variable between two threads, consider using volatile keyword and atomic variables.