Android Thread for a timer - java

public class MainActivity extends Activity
{
int min, sec;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
min = 5;
sec = 0;
final TextView timer1 = (TextView) findViewById(R.id.timer1);
timer1.setText(min + ":" + sec);
Thread t = new Thread() {
public void run() {
sec-=1;
if (sec<0) {
min-=1;
sec=59;
}
timer1.setText(min + ":" + sec);
try
{
sleep(1000);
}
catch (InterruptedException e)
{}
}
};
t.start();
}
}
This is a code for a Thread in Java but it doesn't work. Can you help me?
Its a Timer that counts down from 5 Minutes to 0:00.

In your case you are using threads. So you cannot update ui from the thread other than the ui thread. SO you use runOnUithread. I would suggest you to use a countdown timer or a Handler.
1.CountDownTimer
http://developer.android.com/reference/android/os/CountDownTimer.html
Here's a link to another example. Suggest you to check the link for the count down timer.
Countdowntimer in minutes and seconds
Example:
public class MainActivity extends Activity {
Button b;
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView1);
b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
startTimer(200000);
}
});
}
private void startTimer(long time){
CountDownTimer counter = new CountDownTimer(30000, 1000){
public void onTick(long millisUntilDone){
Log.d("counter_label", "Counter text should be changed");
tv.setText("You have " + millisUntilDone + "ms");
}
public void onFinish() {
tv.setText("DONE!");
}
}.start();
}
}
2.You can use a Handler
Example :
Handler m_handler;
Runnable m_handlerTask ;
int timeleft=100;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
if(timeleft>=0)
{
// do stuff
Log.i("timeleft",""+timeleft);
timeleft--;
}
else
{
m_handler.removeCallbacks(m_handlerTask); // cancel run
}
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
3.Timer
Timer runs on a different thread. You should update ui on the ui thread. use runOnUiThread
Example :
int timeleft=100;
Timer _t = new Timer();
_t.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
Log.i("timeleft",""+timeleft);
//update ui
}
});
if(timeleft>==0)
{
timeleft--;
}
else
{
_t.cancel();
}
}
}, 1000, 1000 );

You are trying to update the UI Thread from a background Thread with
timer1.setText(
which you can't do. You need to use runOnUiThread(), AsyncTask, CountDownTimer, or something similar.
See this answer for an example of runOnUiThread()
But CountDownTimer is nice for things like this.
Also, when posting a question on SO, statements like "it doesn't work." are very vague and often unhelpful. Please indicate the expected results compared to actual results of your code and logcat if the app is crashing.

Related

Only the original thread that created a view hierarchy can touch its views. runOnUIThread and Handlers doesn't stop the error

I'm trying to start a countup timer once I start a new activity on a button click from the first activity, however I keep getting this error. Adding a delay doesn't seem to fix the issue as well and I don't want the delay to be there anyways as there will be an awkward pause.
public class CallActive extends AppCompatActivity {
TextView timerText;
Timer timer;
TimerTask timerTask;
Double time =0.0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getSupportActionBar().hide();
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_callactive);
Intent intent = getIntent();
String text = intent.getStringExtra(MainActivity.EXTRA_INFO);
TextView txtCaller = (TextView) findViewById(R.id.txtCaller2);
txtCaller.setText(text);
timerText = (TextView) findViewById(R.id.timerText);
timer = new Timer();
runOnUiThread(new Runnable() {
#Override
public void run() {
startTimer();
}
});
}
private void startTimer() {
timerTask = new TimerTask() {
#Override
public void run() {
time++;
timerText.setText(getTimerText());
}
};
timer.scheduleAtFixedRate(timerTask, 0, 1000);
}
private String getTimerText() {
int rounded = (int) Math.round(time);
int seconds = ((rounded % 86400) % 3600) % 60;
int minutes = ((rounded % 86400) % 3600) / 60;
return formatTime(seconds,minutes);
}
private String formatTime(int seconds, int minutes)
{
return String.format("%02d",minutes) + " : " + String.format("%02d",seconds);
}
}
I tried using runOnUIThread and Handlers but the same error persists
run() of your TimerTask will be called on a background thread. So, your runOnUiThread() needs to go inside of that run():
private void startTimer() {
timerTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
time++;
timerText.setText(getTimerText());
}
});
}
};
It would be simpler and more efficient to eliminate TimerTask and Timer and use postDelayed().
You look like a little confused about UI elements and UI thread. All UI elements are created by the UI (or main) thread and they can only be modified by it. So although you start you timer using runOnUiThread, this doesn't mean that the TimerTask will run in the main thread. This is where you get confused.
// You define the timertask here but it will not run in this context which is the main thread context
timerTask = new TimerTask() {
#Override
public void run() {
time++;
// This textview is still will be touched from another thread that is not main thread
timerText.setText(getTimerText());
}
};
You must still execute the code that modifies the UI object only within the main thread like following:
timerTask = new TimerTask() {
#Override
public void run() {
time++;
runOnUiThread(()-> timerText.setText(getTimerText()));
}
};

I am using handler for delay in android but it's not working

I want a delay for two seconds. and every 2 seconds I want to change the text, and for that, I am using handler like this, but it's not working it's only showing hello. it's not changing at all it only shows what I write second. The code is like this,
private Handler handler = new Handler();
int i=5;
private TextView textView ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.hello);
textView.setText("Android Things !!");
hello_first.run();
}
private Runnable hello_first = new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");
handler.postDelayed(this,5000);
textView.setText("Hello");
handler.postDelayed(this,2000);
i = i+1;
if(i==5)
handler.removeCallbacks(this);
}
};
You are using postDelayed incorrectly. It looks like you expect it to work the same way Thread.sleep would work. However that is not the case.
Here is a correct implementation of what you are trying to achieve:
private Handler handler = new Handler();
private TextView textView;
private int i = 0;
private boolean flip;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.hello);
handler.post(hello_first);
}
private Runnable hello_first = new Runnable() {
#Override
public void run() {
if(++i == 5) {
handler.removeCallbacks(this);
return;
}
if(flip) {
textView.setText("Nice Work");
} else {
textView.setText("Hello");
}
flip = !flip;
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(2));
}
};
I Hope this will work for you.
Handler handler = new Handler();
Runnable task = new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");
handler.postDelayed(this,2000);
textView.setText("Hello");
handler.postDelayed(this,2000);
}
};
task.run();
For Stopping task
handler.removeCallbacks(task);
Its easy to use like
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
textView.setText("Hello");
},2000);
handler.postDelayed(new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");},5000);
A Handler allows you to send and process Message and Runnable objects
associated with a thread's MessageQueue.
Rectify your postDelayed method.
Causes the Runnable r to be added to the message queue, to be run
after the specified amount of time elapses.
DEMO STRUCTURE
textView.setText("Nice Work");
final Handler handlerOBJ = new Handler();
handlerOBJ.postDelayed(new Runnable() {
#Override
public void run() {
// YOUR WORK
textView.setText("Hello");
}
}, 5000); // 5S delay
You can Log and see what happened actually...
Every time you call handler.postDelayed(this, 5000);
it will create two Runnable instance and send them to the handler. So the number of runnable in the queue increase very quickly.
You can set a text list and index, and then throw the runnable to the handler and postDealyed as 2000 milliseconds. Use the text list and index to see what text should be set to the textview.
try this code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.hello);
textView.setText("Android Things !!");
handler.postDelayed(hello_first,5000);
handler.postDelayed(hello_second,2000);
}
private Runnable hello_first = new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");
}
};
private Runnable hello_second = new Runnable() {
#Override
public void run() {
textView.setText("Hello");
}
};

Execute function after 5 seconds in Android

I am new in android development and now my launcher activity show only 5 seconds and after that I want to check the user is logged in or not function and perform the actions.
here is my code.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exactPreferences = getSharedPreferences("ExactPreference",MODE_PRIVATE);
setContentView(R.layout.activity_landing_page);
session = exactPreferences.getString(Model.getSingleton().SHARED_SESSION_ID,null);
Log.i("Session Id",session);
displayData(); // I want to perform this function after 5 seconds.
}
private void displayData() {
if(session.equals("")){
Intent loginIntent = new Intent(LandingPage.this,
LoginActivity.class);
startActivity(loginIntent);
Log.i("User Logged In", "False");
}
else
{
Intent objIntent = new Intent(LandingPage.this,
IndexPageActivity.class);
startActivity(objIntent);
Log.i("User Logged In", "True");
}
}
You can use the Handler to add some delay.Call the method displayData() as below so that it will be executed after 5 seconds.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
displayData();
}
}, 5000);
Note : Do not use the threads like Thread.sleep(5000); because it will block your UI and and makes it irresponsive.
Assign millisDelayTime variable with the milliseconds you desire to cause a delay. mActivity is an object of Activity for providing Application Context. In your case millisDelayTime should be initialized with 5000
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//your code here
}
}, millisDelayTime);
}
});
Use a CountDownTimer
// There's a TextView txtCount in Main Activity
final int secs = 5;
new CountDownTimer((secs +1) * 1000, 1000) // Wait 5 secs, tick every 1 sec
{
#Override
public final void onTick(final long millisUntilFinished)
{
txtCount.setText("" + (int) (millisUntilFinished * .001f));
}
#Override
public final void onFinish()
{
txtCount.setText("GO!");
finish();
// Time's up - Start the Login Activity
final Intent tnt =
new Intent(getApplicationContext(), LoginActivity.class);
startActivity(tnt);
}
}.start();
Since, Handler is now deprecated so use this code :
new Handler(Looper.myLooper()).postDelayed(new Runnable() {
#Override
public void run() {
//do what you want
}
}, 5000);
Try this, code create CountDownTimer with one tick
timer = new CountDownTimer(5000, 5000)
{
public void onTick(long millisUntilFinished)
{
}
public void onFinish()
{
displayData();
}
};
timer.start();
long delay = 1000;
long period = 50000;
Timer task = new Timer();
task.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
getDriver(sessionManager.getKEY(), ride_id);
}
}, delay, period);
For kotlin way
Handler().postDelayed({
//do something
}, 5000)
When possible, try to avoid using postDelayed. It is a bad practice, since it can lose the reference to the objects that you want to draw on your screen and cause a NPE. Use a Handler instead. First of all, create a global variable Handler in which you will have to "handle" the logic for your code. Do so by using the function handleMessage.
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
if(msg.what == 1){
// your code here
}
}
};
Then, wherever you want to execute it, just call the function:
// 1 is the ID of your process
handler.sendEmptyMessageDelayed(1, 5000);
Please remember that in the onDestroyView method (in a Fragment) or the onDestroy (in an Activity) you will have to call
handler.removeMessages(1)
The best option to achieve this is using a Handler:
int TIME = 5000; //5000 ms (5 Seconds)
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
function(); //call function!
}
}, TIME);

Calling from wrong thread exception

I am trying to develop an application, that uses threads to implement slideshow. I am retrieving the image path from SQLite and displaying them on the ImageView. The problem, where I got struck is, I got confused and so I am unable to understand, from which thread I am calling images() method, where I am actually implementing the slideshow.
I got the Logcat as follows -
09-03 13:47:00.248: E/AndroidRuntime(10642): FATAL EXCEPTION: Thread-151
09-03 13:47:00.248: E/AndroidRuntime(10642): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-03 13:47:00.248: E/AndroidRuntime(10642): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5908)
09-03 13:47:00.248: E/AndroidRuntime(10642): at com.example.fromstart.MainActivity.images(MainActivity.java:90)
09-03 13:47:00.248: E/AndroidRuntime(10642): at com.example.fromstart.MainActivity$2.run(MainActivity.java:59)
09-03 13:47:00.248: E/AndroidRuntime(10642): at java.lang.Thread.run(Thread.java:841)
MainActivity.java:
public class MainActivity extends Activity
{
ImageView jpgView;
TextView tv;
//adapter mDbAdapter;
adapter info = new adapter(this);
String path;
Handler smHandler = new Handler()
{
public void handleMessage(Message msg)
{
TextView myTextView =
(TextView)findViewById(R.id.textView1);
myTextView.setText("Button Pressed");
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jpgView = (ImageView)findViewById(R.id.imageView1);
tv = (TextView) findViewById(R.id.textView1);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
final Runnable runnable = new Runnable()
{
public void run()
{
images();
}
};
int delay = 1000; // delay for 1 sec.
int period = 15000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
smHandler.post(runnable);
}
}, delay, period);
Thread mythread = new Thread(runnable);
mythread.start();
return true;
}
public void handleMessage(Message msg)
{
String string = "sample";
TextView myTextView = (TextView)findViewById(R.id.textView1);
myTextView.setText(string);
}
public void images()
{
try
{
for(int i=0;i<=20;i++)
{
path = info.getpath();
Bitmap bitmap = BitmapFactory.decodeFile(path);
jpgView.setImageBitmap(bitmap);
}
}
catch(NullPointerException er)
{
String ht=er.toString();
Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
}
}
}
I am a newbie to android, just now started working on Threads. If you find any mistakes in my code, please point out those and please suggest me, the right way to deal with this problem.
Thanks in advance.
UPDATE:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Handler mHandler = new Handler();
// Create runnable for posting
runOnUiThread(new Runnable()
{
public void run()
{
images();
}
});
int delay = 1000; // delay for 1 sec.
int period = 15000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
images();
}
}, delay, period);
}
public void images()
{
try
{
Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG).show();
path = info.getpath();
Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_LONG).show();
Bitmap bitmap = BitmapFactory.decodeFile(path);
Toast.makeText(getApplicationContext(), "3", Toast.LENGTH_LONG).show();
jpgView.setImageBitmap(bitmap);
Toast.makeText(getApplicationContext(), "4", Toast.LENGTH_LONG).show();
}
catch(NullPointerException er)
{
String ht=er.toString();
Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
}
}
}
You cannot update/access ui from from a thread.
You have this
public void run()
{
images();
}
And in images you have
jpgView.setImageBitmap(bitmap);
You need to use runOnUiThread for updating ui.
runOnUiThread(new Runnable() {
#Override
public void run() {
// do something
}
});
TimerTask also runs on a different thread. So you have use a Handler for updati ui.
You can use a handler.
Edit:
Handler m_handler;
Runnable m_handlerTask ;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
// do something. call images()
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
If you still wish to use a timer task use runOnUiThread
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
runOnUiThread(new Runnable() {
#Override
public void run() {
images();
}
});
}
}, delay, period);
To update UI from any other Thread you must use
runOnUiThread(<Runnable>);
which will update your UI.
Example:
runOnUiThread(
new Runnable()
{
// do something on UI thread Update UI
});

Use timertask to update clock each X seconds?

I'm trying to update my digital clock using timertask. I have created a function called updateClock() which sets the hours and minutes to the current time but I haven't been able to get it to run periodically. From what I've read in other answers one of the best options is to use timertask however I haven't been able to make any example I found online work inside an Android activity.
This is what I've written so far:
public class MainActivity extends Activity {
TextView hours;
TextView minutes;
Calendar c;
int cur_hours;
int cur_minutes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.clock_home);
hours = (TextView) findViewById(R.id.hours);
minutes = (TextView) findViewById(R.id.minutes);
updateClock();
}
public void updateClock() {
c = Calendar.getInstance();
hours.setText("" + c.get(Calendar.HOUR));
minutes.setText("" + c.get(Calendar.MINUTE));
}
public static void init() throws Exception {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateClock(); // ERROR
}
}, 0, 1 * 5000);
}
}
How can I make it work?
Use runOnUiThread for updating Ui from Timer Thread
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
MainActivity.this.runOnUiThread (new Runnable() {
public void run() {
updateClock(); // call UI update method here
}
}));
}
}, 0, 1 * 5000);
}
if you just need updates every minute, you can also listen to the ACTION_TIME_TICK broadcast event.
private boolean timeReceiverAttached;
private final BroadcastReceiver timeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateClock();
}
};
private Handler handler = new Handler();
#Override
protected void onResume() {
super.onResume();
updateClock();
if (!timeReceiverAttached) {
timeReceiverAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(timeReceiver, filter, null, handler);
}
}
#Override
protected void onPause() {
super.onPause();
if (timeReceiverAttached) {
unregisterReceiver(timeReceiver);
timeReceiverAttached = false;
}
}
OR, periodically post the Runnable to the Handler of UI thread. Also, pause and resume tasks to save battery.
public class MyActivity extends Activity {
private final Handler mHandler = new Handler();
private final Timer mTimer = new Timer();
#Override
protected void onResume() {
super.onResume();
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
//---update UI---
}
});
}
},0,5000);
}
#Override
protected void onPause() {
super.onPause();
mTimer.cancel();
}
}

Categories

Resources