For the problem I am solving, I have to run a series of calls at periodic intervals. To achieve this, I have implemented TimerTask. However, I also want to notify the timertask sometimes and need to call the same methods when certain conditions are met even if the timer did not expire. My code looks similar to this.
//File TimerTaskA.java
public class TimerTaskA extends TimerTask
{
#Override
public void run()
{
processEvent1();
processEvent2();
processEvent3();
}
}
//File ProcessEventManager.java
public class ProcessEventManager
{
public TimerTaskA timerTask;
public ProcessEventManager()
{
initTimerTask();
}
public void initTimerTask()
{
Timer timer = new Timer("TimerTaskA", true);
timerTask == new TimerTaskA();
timer.schedule(timerTask , 0, 10000);
}
public void conditionalTask()
{
long time = System.currentTimeMillis();
// some condition statement. here it happens to be time in millisecs ends with 2 or 3.
if (time%10 == 2 || time%10 == 3)
timerTask.run();
}
}
In the ProcessEventManager.conditionalTask() method is it correct to call TimerTask's run() method directly to get through this situation? Is there a better way design wise to solve something like this?
The processEvent methods might be time consuming methods, and I do not want the thread running ProcessEventManager to be blocked while executing those methods. For the TimerTask to take care of running those methods in both the cases when timer expires as well as the condition in ProcessEventManager.conditionalTask is satisfied, what is the best way to do it?
Basically, yes, it is possible to do as you wrote, but a clearer way will be to call some processing method from inside the TimerTask, and when you want to perform this operation, call it directly, not through the TimerTask object.
public class TimerTaskA extends TimerTask
{
public void doCoolThings()
{
processEvent1();
processEvent2();
processEvent3();
}
#Override
public void run()
{
doCoolThings();
}
}
in the other class, when needed:
timerTask.doCoolThings();
The reason as I see it, is mainly because the purpose of run is to serve as the thread (or caller) entry point, not to do a specific task.
Related
I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}
How do I accomplish a "wait for idle" model with the properties:
When a method do() is called, after X delay, a close() method will be called.
If I call the do() method again before X time has passed, the call to close() must be postponed.
EXAMPLE
Scenario 1: (for timeout = 10 secs):
The user calls do() at time 0.
At time 10, the close() method is called because the user has not called do() again.
Scenario 2: (also timeout = 10 secs):
The user calls do() at time 0. (so at 10 the close() method should be called).
At time of 8, the user calls do() again.
At time of 10 nothing happens because the close() was postponed 10 seconds.
At time 18, the close() method is called, because the user has not called do() again since 8.
What i have tried:
private static final long delay = 10000;
private Timer t;
private TimerTask tt;
public void do() {
...
// check old timer first:
if (t != null) t.cancel();
// create new timer
t = new Timer();
tt = new TimerTask() {
#Override
public void run() {
close();
}
}
// run it
t.schedule(tt, System.currentTimeMillis() + delay);
}
private void close() {
// do some cleanup here
}
This code is very ugly.
It's also very unefficient and memory-consuming, because the do() function is getting called about 50 times per second.
What should I do to get this working in an efficient and neat way? (Is it really so hard?)
You are on a right way and it is not a hard one.
Here is what I want to suggest you. Create timer only once. Make it a member of class. Create its instance in constructor.
When method is called create a task as you already do now. You can however create separate class and even create it instance in advance and when do() method is called just schedule it, so the close() will be called according to your schedule.
When do() is called cancel the previously created close task. This will make sure that you will not close anything if method do() was called again.
BTW since do is a reserved word in java you cannot call method this way. This means that your code even cannot be compiled. Change the name.
Set a 10 second timer task when you open()
Keep a variable long lastCall which gets set to System.currentTimeMillis() from doIt()
In the time task body, check whether lastCall is within 10 seconds. If so, reschedule the timer task for the remaining time. If not, call close()
Don't forget to synchronize on something when you read to or write from lastCall
I've found a suitable solution:
public class TimerExample {
private TimerTask tt;
ScheduledFuture<?> future;
private ScheduledThreadPoolExecutor s;
public TimerExample() {
s = new ScheduledThreadPoolExecutor(1);
tt = new TimerTask() {
#Override
public void run() {
close();
}
};
doSomething();
}
public void doSomething() {
if (future != null) future.cancel(true);
future = s.schedule(tt, 3000, TimeUnit.MILLISECONDS);
System.out.println("do");
}
public void close() {
System.out.println("Close");
}
}
I'm playing around with Java and I've got myself a class for an NPC in a game. One method is called when they collide with another object:
public void collided_in_to(Entity ent) {
if(ent.equals(game.player)) {
this.speak = "Ouch!";
}
}
What I want to do, which I figured was going to be simple, is set this.speak to "" after a given amount of seconds. Coming from a web background, I was looking for an equivalent of Javascripts setTimeout().
I've tried using various timer snippets, such as using Swing timers, but in that case it seemed like every timer would call the same public void actionPerformed(ActionEvent e) method, and so with multiple timers for different events I had no way to differentiate between them. Others used inline anonymous classes, but then I have no way to pass non-final parameters to it.
Is there something I'm missing for this use case, where I want very small simple things to happen after a set time? (Instance method called, variable set, etc.)
Thanks!
How about writing you own simple Timer? I would think of something like this :
public class Timer {
long start = 0;
long delay;
public Timer(long delay) {
this.delay = delay;
}
public void start() {
this.start = System.currentTimeMillis();
}
public boolean isExpired() {
return (System.currentTimeMillis() - this.start) > this.delay;
}
}
Then instantiate the Timer class as a class member and call start() when you want to start the timer.
In your method you call
public void collided_in_to(Entity ent) {
if(ent.equals(game.player)) {
if(this.timer.isExpired()) this.speak = "";
else this.speak = "Ouch!";
}
}
If you're using a game loop you could simply make a seconds passed verification.
Have you considered threads? Thread.sleep() can be used fairly effectively to time it.
I just want to run a function myFunction() every X milliseconds while an external flag is true. However I've had no luck with Threads (app crashes), Timers (app crashes). Handlers/runnables are a bit better but typically I'll have something like:
Runnable rr = new Runnable() {
public void run() {
if (flag1 == true) {
myFunction();
} else {
return;
}
}
};
handler.postDelayed(rr, 1000);
But then the problem is execution will come one after another after 1000 milliseconds. I want one execution of myFunction to happen, wait 1000ms, call myFunction, wait 1000ms, call myFunction, etc, until flag1 becomes false.
I've been stuck on this for a while, so any help is much appreciated.
EDIT - more question info
The handler is defined as follows:
private Handler handler = new Handler();
And its class is a BroadcastReceiver where I'm trying to listen for flag changes based on asynchronous events from external hardware.
This will loop and check the flag every second for the lifetime of the application.
Thread myThread = new Thread(new UpdateThread());`
myThread.start();`
public class UpdateThread implements Runnable {
#Override
public void run() {
while(true)
{
if (flag1 == true)
myFunction();
myThread.sleep(1000);
}
}
also you may want to look at a service
http://developer.android.com/reference/android/app/Service.html
I'm calling this tasks:
TimerTask taskA = new ThreadA(this);
TimerTask taskB = new ThreadB(this);
tasks.add(taskA);
tasks.add(taskB);
timer.schedule(taskA, 10000);
timer.schedule(taskB, 5000);
And here are the two TimerTasks:
public class ThreadA extends TimerTask {
private Ghost ghost;
public GhostThread(Ghost ghost) {
this.ghost = ghost;
}
#Override
public void run() {
ghost.stopBeingDeadAndBeAwesomeAgain();
}
}
public class ThreadB extends TimerTask {
private Ghost ghost;
public WarnThread(Ghost ghost) {
this.ghost = ghost;
}
#Override
public void run() {
ghost.beDeadAgain();
}
}
As you can see, I just call a method after 5 resp. 10 seconds. From time to time I would like to pause the "countdown". This means i want that the time until the 5 seconds are passed isn't running anymore. And then in a later point in time, I would like to resume it.
How can I achieve that??
The simplest solution would be to simply make a copy of the TimerTask, cancel it to pause, purge if you want, and then reschedule it to resume.
// pause
long timeLeft = 5000 - (new Date().getTime() - taskB.scheduledExecutionTime());
ThreadB taskBpaused = taskB.clone();
taskB.cancel();
timer.purge();
taskB = taskBpaused;
// resume
timer.schedule(taskB, timeLeft, ...);
Important note: if the task hasn't run yet, then this won't work. Google's documentation states that if it hasn't run, scheduledExecutionTime() will return an undefined value, and I don't have the capability to test what exactly that means at the moment. Needless to say, if you aren't sure it's already run, you'll need some kind of conditional to make sure the value isn't undefined.