Reputation: 677
I want to call my function every 10 seconds with a timer and my function has a handler it shows an error:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
My function:
public void startData(){
doBindService();
new Handler().post(mQueueCommands);
}
this startData() has a public variable "btIsConnected" , whenever
btIsConnected== true
, I want to stop calling it, otherwise for the first two minutes I want to call startData() every 10 seconds
class startLiveDataTimerTask extends TimerTask{
public void run(){
startData();
}
}
private void tryConnectEveryTenSeconds() {
Timer timer = new Timer();
timer.schedule(new startLiveDataTimerTask(), 0, 10000);
}
in onCreate()
:
long futureTimeInTwoMinute = System.currentTimeMillis() + 120000;
Intent i = new Intent(ObdConstants.StartLiveData.getValue()); sendBroadcast(i); // this broadcaster is used to call StartData() for the first time
if(System.currentTimeMillis()<futureTimeInTwoMinute){
// how do I make a time counter appropriately?
if(btIsConnected){
Log.d(TAG, "is connected!");
//do nothing
}else{
Log.d(TAG, "try to connect every ten seconds....");
tryConnectEveryTenSeconds();
}
}
Upvotes: 2
Views: 1814
Reputation: 7082
If you want to use the Handler architecture, there will be no use for the Timer object.
First, obtain the Handler. For the example I will use the main Handler
(UIThread), but you may also create your own, with a new Looper
.
So, lets start the looped task like this:
private void tryConnectEveryTenSeconds() {
Handler handler = new Handler(Looper.getMainLooper()); //This gets the UIThread Handler
handler.postDelayed(new startLiveDataTimerTask(), 10000); //This posts the task ONCE, with 10 sec delay
}
And now for the task:
public void startData(){
doBindService();
Handler handler = new Handler(Looper.getMainLooper());
handler.post(mQueueCommands); //I expect this is what you want. If not and you want a completely new Handler, you will need to create it on a new Thread
handler.postDelayed(new startLiveDataTimerTask(), 10000); //This posts the task AGAIN, with 10 seconds delay
}
Please mind that all the methods will be called on the UIThread. If you want the mQueueCommands task to run on a new Handler
on a new Thread, you need to create it.
EDIT:
The invoking code should look something like this:
long futureTimeInTwoMinute = System.currentTimeMillis() + 120000;
Intent i = new Intent(ObdConstants.StartLiveData.getValue()); sendBroadcast(i);
tryConnectEveryTenSeconds();
while(System.currentTimeMillis()<futureTimeInTwoMinute){
if(btIsConnected){
Log.d(TAG, "is connected!");
//do nothing
}else{
Log.d(TAG, "Not connected yet...");
}
}
You do not want to fire the looping method more than once :-)
Upvotes: 2
Reputation: 93569
Handlers can only be created on Threads that are in a Looper. The main UI thread is in a Looper, so Handlers can be created there. A normal Thread or AsyncTask is not, so they cannot create Handlers. Assuming you want to post to the UI Thread, you need to create the Handler on the UI thread.
As an aside, its very unusual to see code creating a new Handler like that. Generally the pattern is to create a single Handler in your constructor and post to it. Creating new Handlers like that is inefficient at best and a bug at worst.
Upvotes: 1