How to use Handler / runnable? - android

I would like my code runs all the one minut..
Can anyone explain me how to do it?
private Handler myHandler;
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//DO WORK
Toast.makeText(getApplicationContext(), " Hello",Toast.LENGTH_SHORT).show();
myHandler.postDelayed(this,60000);
}
};
#Override
public void onCreate() {
super.onCreate();
//call function
myHandler = new Handler();
//
myHandler.postDelayed(myRunnable,60000);
Log.d(this.getClass().getName(), "onCreate");
}

watch this http://goo.gl/DRdaUi
BTW 60 second is a very long time for thread to run! If you have something that runs this long consider using android service instead of thread.
Also do you need to use handler? think again, most of the time there is no need for that. AsyncTask is android first option for multithreading and its a lot simpler. unless AsyncTask can not handle what you have in your mind don't use any other method.

A Timer is a valid solution but it will not execute on the UI thread. And your code tells me this is what you want.
The simplest way to do that would be via a handler and a repeating task:
final Handler handler = new Handler(); // ui thread handler
handler.postDelayed(new MyRunnable(handler), INETRVAL);
Where:
class MyRunnable implements Runnable {
#Override
public void run() {
// do periodical action here
// and.. repeat your task <------------
handler.postDelayed(new MyRunnable(handler), INETRVAL);
}
}

Related

How can I run a specific type of task off the UI thread?

I want to run a function whenever a recyclerview binds a view. It's a really long operation, so I have to keep it off the UI thread. I know how to create a thread, but how can I use the same thread to always run the content of the onBindViewHolder method on the second thread without creating a new one every time the specific function gets executed ?
#Override
public void onBindViewHolder (final Adapter adapter, RecyclerView.ViewHolder holder, final int position) {
new Thread(new Runnable() {
#Override
public void run () {
theMethod(adapter, holder, position);
}
}).start();
}
Consider using a HandlerThread, then scheduling work against that thread with a Handler created with the HandlerThread's Looper. You will have to remember the shut down the thread at the end of the activity, of course, or it will stick around indefinitely and maybe leak objects.
For example:
HandlerThread thread = new HandlerThread("Give Me a Name");
thread.start();
Looper looper = thread.getLooper();
Handler handler = new Handler(mServiceLooper);
// use handler to post work to the thread
These lines of code are cribbed directly from IntentService, which does exactly the same thing you want, except in a service. Maybe that's even what you actually want to use!
Create new thread which can do jobs with a queue.
class YourThread extends Thread {
public List<Job> queue = new ArrayList<>();
#Override
public void run(){
while(queue.size() == 0)
wait(); // nothing to do, wait...
Job job = queue.get(queue.size() - 1); // pop queue
queue.remove(queue.size() - 1);
dosomething(job);
}
public void addJob(....){
...
queue.add(job, 0);
}
}
and onBindViewHolder
YourThread thread = new ...
thread.start()
#Override
public void onBindViewHolder (final Adapter adapter, RecyclerView.ViewHolder holder, final int position) {
thread.addJob(...);
// remember that after the job finished, the item may be recycled
}
You can achieve it by using Looper. The main purpose of Looper is this only, to keep the thread alive and waiting for new messages(Runnables).
Here's a sample code from the official documentation :
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Now, you can post new runnables (messages) to the thread using the handler. Something like this :
handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
}
});
Edit :
The method provided above is more of 'do-it-yourself'. There's a special class in android that can do this automatically for you, i.e. HandlerThread. Sample code :
HandlerThread thread = new HandlerThread("name");
thread.start();
Looper looper = thread.getLooper();
Handler handler = new Handler(looper);
Now you can post runnables to this handler.

Can this be garbage-collected?

In existing (presumably) working code I see the following construct:
void someFunc() {
some_irrelevant_code();
new Runnable() {
Handler handler = new Handler();
#Override
public void run()
{
//will run each 5 seconds
doSomething();
if (!needStopSomeThread)
{
handler.postDelayed(this, 5000);
}
}
}.run();
}
I wonder if the Runnable and the Handler may be garbage-collected at an arbitrary moment. It looks like only the runnable references the handler, and only the handler references the runnable, so they may be both garbage-collected, unless Android has a data structure referencing one of them, e.g. the handler.
1) Can they both (the handler and the runnable) get garbage-collected?
2) If they can get garbage-collected, how can I prove it actually happens?

Android - Running a delayed task from a Worker Thread (NotificationListenerService Thread)

I need to call a delayed method(runnable) from the NLService thread. However the method never gets called. I would appreciate any help.
public class NLService extends NotificationListenerService {
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
if(sbn.getPackageName().contains("mv.purple.aa")){
AudioManager amanager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
amanager.setStreamMute(AudioManager.STREAM_NOTIFICATION, true);
//This is the code I am having issues with.
//I used this code to call the method. However it is not working.
private Handler handler = new Handler();
handler.postDelayed(runnable, 100);
}
}
//I want to call the following method
private Runnable runnable = new Runnable() {
#Override
public void run() {
foobar();
}
};
}
The NotificationListenerService is a service which gets activated when notifications are posted within the framework. It does this via a Binder notification internal to the framework, so your onNotificationPosted() callback is being called from one of the binder pool threads, not the usual main thread of your app. In essence, the Handler you are creating is associating itself with a Looper which never gets called because the thread is managed by the internal binder framework rather than the usual main thread or other thread you may create.
Try this: create a HandlerThread the first time your callback is hit (and save it off) and start it. Toss your Runnable over to a Handler you create which is bound to the Looper in the HandlerThread.
There is also a "simpler" solution.
You can create a new Handler inside your onCreate(). Save it as class variable and call it when ever you want again.
Example:
public class NotificationListener extends NotificationListenerService
private mHandler handler;
public void onCreate() {
super.onCreate();
handler = new Handler();
}
#Override
public void onNotificationPosted(StatusBarNotification statusBarNotification) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Do something special here :)
}
}, 5*1000);
}
....
// Override other importand methods
....
}

What code do i implement to have a time limit in my game

I'm createing a quiz that has a time limit and i dont know what to implement to have a timelimit in my level 1 class. what should i implement? can you show me a complete code?
am i correct?
private Runnable task = new Runnable() {
public void run() {
Intent intent = new Intent(getApplicationContext(),MainMenu.class);
startActivity(intent);
}
};
private void onCreate() {
Handler handler = new Handler();
handler.postDelayed(task, 60000);
There are different ways to do it. One way is to use a Runnable and a Handler.
First, define the Runnable:
private Runnable task = new Runnable() {
public void run() {
Log.i(TAG, "Time limit reached!");
// Execute code here
}
};
Then you call it (say at the start of the level, onCreate) with this Handler and postDelayed
Handler handler = new Handler();
handler.postDelayed(task, 60000);
The code within the run() method of the Runnable will execute 60 seconds after you call postDelayed
If you need regular notifications you can also use a CountDownTimer

Android unit tests with multiple threads

I have a problem with unit tests in Android.
My object MyObject has a method start() like this :
public void start() {
final Handler onStartHandler = new Handler();
new Thread() {
#Override
public void run() {
super.run();
onStartHandler.post(new Runnable() {
#Override
public void run() {
mIsRunning = true;
onStart();
}
});
}
}.start();
}
And I want to test that onStart() is called.
So I tried something like that :
public void testOnStartIsCalled() {
assertFalse("onStart() should not be called", mMyObject.isRunning());
mMyObject.start();
assertTrue("onStart() should be called", mMyObject.isRunning());
mMyObject.stop();
assertFalse("onStop() should be called", mMyObject.isRunning());
}
But it doesn't work, I guess it's because it's in a Handler and a new Thread.
My test class extends AndroidTestCase.
What should I do ? What is the best practice for this case ?
Regards.
When I deal with testing some multi-threaded code I try to let the program take as much of its natural flow as possible. Additionally, I avoid the use of sleep statements since you don't get any guarantees that the sleep interval you've chosen is enough to allow the subject of your test to finish what it's doing; you often end up having to choose sleep intervals that are too large and it forces a much slower execution of your test cases.
I would recommend that you try to add some code into the class you're testing, in this case MyObject, which call a listener whenever something happens. It seems that you already have callback methods for onStart() and onStop()(if those are events/callbacks), so those should be getting invoked and you should use them to control the flow of your test. When you get an onStart() event, you should then call stop() and wait for an onStop() event.
Update
First and foremost, you have redundant code:
public void start() {
final Handler onStartHandler = new Handler();
new Thread() {
#Override
public void run() {
super.run();
onStartHandler.post(new Runnable() {
#Override
public void run() {
mIsRunning = true;
onStart();
}
});
}
}.start();
}
Either start a new thread to call onStart() or schedule the runnable on the Handler's thread queue.
Version 1- remove the handler and just let the code be executed in a new thread:
public void start() {
new Thread() {
#Override
public void run() {
super.run();
mIsRunning = true;
onStart();
}
}.start();
}
Version 2- only use the handler to asynchronously execute the callback:
public void start() {
final Handler onStartHandler = new Handler();
onStartHandler.post(new Runnable() {
#Override
public void run() {
mIsRunning = true;
onStart();
}
});
}
And second: I noticed is that if you don't have a Looper, then whatever you post with the Handler will be ignored (thus it will never be called). For more information on the Looper-Handler pattern see the article: Android Guts: Intro to Loopers and Handlers. The Looper and the Handler are supposed to be attached to the same thread (usually the main thread). Additionally, if you're creating the Handler on a separate thread as your Looper, then you'll run into the same problem: anything you post with the Handler will be ignored.
Here are a few more good questions and articles on loopers and handlers:
Just do IT: looper and handler in android
Handler-Looper implementation in Android
The relationships between Looper, Handler and MessageQueue is shown below:
The problem here is that you are calling onStart() which invokes a new thread, and then immediately ask if it is started. There is startup time for the new thread and while that is happening, your test is asking if it is started -- it's not YET.
I bet if you waited by using Thread.sleep(), or a loop, you'd find it is started "eventually".
What is it you're actually trying to test?
If you need the new thread, you might want to read up on threads, synchronize, etc.
http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html

Categories

Resources