How to add a timer/clock in android studio [duplicate] - java

I want to be able to call the following method after a specified delay.
In objective c there was something like:
[self performSelector:#selector(DoSomething) withObject:nil afterDelay:5];
Is there an equivalent of this method in android with java?
For example I need to be able to call a method after 5 seconds.
public void DoSomething()
{
//do something here
}

Kotlin
Handler(Looper.getMainLooper()).postDelayed({
//Do something after 100ms
}, 100)
Java
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
}
}, 100);
The class to import is android.os.handler.

I couldn't use any of the other answers in my case.
I used the native java Timer instead.
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// this code will be executed after 2 seconds
}
}, 2000);

Note: This answer was given when the question didn't specify Android as the context. For an answer specific to the Android UI thread look here.
It looks like the Mac OS API lets the current thread continue, and schedules the task to run asynchronously. In the Java, the equivalent function is provided by the java.util.concurrent package. I'm not sure what limitations Android might impose.
private static final ScheduledExecutorService worker =
Executors.newSingleThreadScheduledExecutor();
void someMethod() {
⋮
Runnable task = new Runnable() {
public void run() {
/* Do something… */
}
};
worker.schedule(task, 5, TimeUnit.SECONDS);
⋮
}

For executing something in the UI Thread after 5 seconds:
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
//Do something here
}
}, 5000);

Kotlin & Java Many Ways
1. Using Handler
Handler().postDelayed({
TODO("Do something")
}, 2000)
2. Using TimerTask
Timer().schedule(object : TimerTask() {
override fun run() {
TODO("Do something")
}
}, 2000)
Or even shorter
Timer().schedule(timerTask {
TODO("Do something")
}, 2000)
Or shortest would be
Timer().schedule(2000) {
TODO("Do something")
}
3. Using Executors
Executors.newSingleThreadScheduledExecutor().schedule({
TODO("Do something")
}, 2, TimeUnit.SECONDS)
In Java
1. Using Handler
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Do something
}
}, 2000);
2. Using Timer
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// Do something
}
}, 2000);
3. Using ScheduledExecutorService
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = new Runnable() {
public void run() {
// Do something
}
};
worker.schedule(runnable, 2, TimeUnit.SECONDS);

you can use Handler inside UIThread:
runOnUiThread(new Runnable() {
#Override
public void run() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//add your code here
}
}, 1000);
}
});

Thanks for all the great answers, I found a solution that best suits my needs.
Handler myHandler = new DoSomething();
Message m = new Message();
m.obj = c;//passing a parameter here
myHandler.sendMessageDelayed(m, 1000);
class DoSomething extends Handler {
#Override
public void handleMessage(Message msg) {
MyObject o = (MyObject) msg.obj;
//do something here
}
}

See this demo:
import java.util.Timer;
import java.util.TimerTask;
class Test {
public static void main( String [] args ) {
int delay = 5000;// in ms
Timer timer = new Timer();
timer.schedule( new TimerTask(){
public void run() {
System.out.println("Wait, what..:");
}
}, delay);
System.out.println("Would it run?");
}
}

More Safety - With Kotlin Coroutine
Most of the answers use Handler but I give a different solution to delay in activity, fragment, view model with Android Lifecycle ext. This way will auto cancel when the lifecycle begins destroyed - avoid leaking the memory or crashed app
In Activity or Fragment:
lifecycleScope.launch {
delay(DELAY_MS)
doSomething()
}
In ViewModel:
viewModelScope.lanch {
delay(DELAY_MS)
doSomething()
}
In suspend function: (Kotlin Coroutine)
suspend fun doSomethingAfter(){
delay(DELAY_MS)
doSomething()
}
If you get an error with the lifecycleScope not found! - import this dependency to the app gradle file:
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"

If you have to use the Handler, but you are into another thread, you can use runonuithread to run the handler in UI thread. This will save you from Exceptions thrown asking to call Looper.Prepare()
runOnUiThread(new Runnable() {
#Override
public void run() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 1 second
}
}, 1000);
}
});
Looks quite messy, but this is one of the way.

I prefer to use View.postDelayed() method, simple code below:
mView.postDelayed(new Runnable() {
#Override
public void run() {
// Do something after 1000 ms
}
}, 1000);

Here is my shortest solution:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
}
}, 100);

If you are using Android Studio 3.0 and above you can use lambda expressions. The method callMyMethod() is called after 2 seconds:
new Handler().postDelayed(() -> callMyMethod(), 2000);
In case you need to cancel the delayed runnable use this:
Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);
// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);

final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
//DO SOME ACTIONS HERE , THIS ACTIONS WILL WILL EXECUTE AFTER 5 SECONDS...
}
});
}
}, 5000);

I suggest the Timer, it allows you to schedule a method to be called on a very specific interval. This will not block your UI, and keep your app resonsive while the method is being executed.
The other option, is the wait(); method, this will block the current thread for the specified length of time. This will cause your UI to stop responding if you do this on the UI thread.

So there are a few things to consider here as there are so many ways to skin this cat. Although answers have all already been given selected and chosen. I think it's important that this gets revisited with proper coding guidelines to avoid anyone going the wrong direction just because of "majority selected simple answer".
So first let's discuss the simple Post Delayed answer that is the winner selected answer overall in this thread.
A couple of things to consider. After the post delay, you can encounter memory leaks, dead objects, life cycles that have gone away, and more. So handling it properly is important as well. You can do this in a couple of ways.
For sake of modern development, I'll supply in KOTLIN
Here is a simple example of using the UI thread on a callback and confirming that your activity is still alive and well when you hit your callback.
Handler(Looper.getMainLooper()).postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
However, this is still not perfect as there is no reason to hit your callback if the activity has gone away. so a better way would be to keep a reference to it and remove it's callbacks like this.
private fun showFacebookStylePlus1NewsFeedOnPushReceived(){
A35Log.v(TAG, "showFacebookStylePlus1NewsFeedOnPushReceived")
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.VISIBLE
mHandler.postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
}
}
and of course handle cleanup on the onPause so it doesn't hit the callback.
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(null)
}
Now that we have talked through the obvious, let's talk about a cleaner option with modern day coroutines and kotlin :). If you aren't using these yet, you are really missing out.
fun doActionAfterDelay()
launch(UI) {
delay(MS_TO_DELAY)
actionToTake()
}
}
or if you want to always do a UI launch on that method you can simply do:
fun doActionAfterDelay() = launch(UI){
delay(MS_TO_DELAY)
actionToTake()
}
Of course just like the PostDelayed you have to make sure you handle canceling so you can either do the activity checks after the delay call or you can cancel it in the onPause just like the other route.
var mDelayedJob: Job? = null
fun doActionAfterDelay()
mDelayedJob = launch(UI) {
try {
delay(MS_TO_DELAY)
actionToTake()
}catch(ex: JobCancellationException){
showFancyToast("Delayed Job canceled", true, FancyToast.ERROR, "Delayed Job canceled: ${ex.message}")
}
}
}
}
//handle cleanup
override fun onPause() {
super.onPause()
if(mDelayedJob != null && mDelayedJob!!.isActive) {
A35Log.v(mClassTag, "canceling delayed job")
mDelayedJob?.cancel() //this should throw CancelationException in coroutine, you can catch and handle appropriately
}
}
If you put the launch(UI) into the method signature the job can be assigned in the calling line of code.
so moral of the story is to be safe with your delayed actions, make sure you remove your callbacks, or cancel your jobs and of course confirm you have the right life cycle to touch items on your delay callback complete. The Coroutines also offers cancelable actions.
Also worth noting that you should typically handle the various exceptions that can come with coroutines. For example, a cancelation, an exception, a timeout, whatever you decide to use. Here is a more advanced example if you decide to really start utilizing coroutines.
mLoadJob = launch(UI){
try {
//Applies timeout
withTimeout(4000) {
//Moves to background thread
withContext(DefaultDispatcher) {
mDeviceModelList.addArrayList(SSDBHelper.getAllDevices())
}
}
//Continues after async with context above
showFancyToast("Loading complete", true, FancyToast.SUCCESS)
}catch(ex: JobCancellationException){
showFancyToast("Save canceled", true, FancyToast.ERROR, "Save canceled: ${ex.message}")
}catch (ex: TimeoutCancellationException) {
showFancyToast("Timed out saving, please try again or press back", true, FancyToast.ERROR, "Timed out saving to database: ${ex.message}")
}catch(ex: Exception){
showFancyToast("Error saving to database, please try again or press back", true, FancyToast.ERROR, "Error saving to database: ${ex.message}")
}
}

For a Simple line Handle Post delay, you can do as following :
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// Do someting
}
}, 3000);
I hope this helps

You can use this for Simplest Solution:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Write your code here
}
}, 5000); //Timer is in ms here.
Else, Below can be another clean useful solution:
new Handler().postDelayed(() ->
{/*Do something here*/},
5000); //time in ms

You can make it much cleaner by using the newly introduced lambda expressions:
new Handler().postDelayed(() -> {/*your code here*/}, time);

Using Kotlin, we can achieve by doing the following
Handler().postDelayed({
// do something after 1000ms
}, 1000)

If you use RxAndroid then thread and error handling becomes much easier. Following code executes after a delay
Observable.timer(delay, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> {
// Execute code here
}, Throwable::printStackTrace);

I created simpler method to call this.
public static void CallWithDelay(long miliseconds, final Activity activity, final String methodName)
{
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
try {
Method method = activity.getClass().getMethod(methodName);
method.invoke(activity);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}, miliseconds);
}
To use it, just call : .CallWithDelay(5000, this, "DoSomething");

Below one works when you get,
java.lang.RuntimeException: Can't create handler inside thread that
has not called Looper.prepare()
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
}
}, 100);

It's very easy using the CountDownTimer.
For more details https://developer.android.com/reference/android/os/CountDownTimer.html
import android.os.CountDownTimer;
// calls onTick every second, finishes after 3 seconds
new CountDownTimer(3000, 1000) {
public void onTick(long millisUntilFinished) {
Log.d("log", millisUntilFinished / 1000);
}
public void onFinish() {
// called after count down is finished
}
}.start();

I like things cleaner:
Here is my implementation, inline code to use inside your method
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
}
}, 100);

everybody seems to forget to clean the Handler before posting a new runnable or message on it. Otherway they could potentially accumulate and cause bad behaviour.
handler.removeMessages(int what);
// Remove any pending posts of messages with code 'what' that are in the message queue.
handler.removeCallbacks(Runnable r)
// Remove any pending posts of Runnable r that are in the message queue.

Here is another tricky way: it won't throw exception when the runnable change UI elements.
public class SimpleDelayAnimation extends Animation implements Animation.AnimationListener {
Runnable callBack;
public SimpleDelayAnimation(Runnable runnable, int delayTimeMilli) {
setDuration(delayTimeMilli);
callBack = runnable;
setAnimationListener(this);
}
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
callBack.run();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
}
You can call the animation like this:
view.startAnimation(new SimpleDelayAnimation(delayRunnable, 500));
Animation can attach to any view.

Here is the answer in Kotlin you lazy, lazy people:
Handler().postDelayed({
//doSomethingHere()
}, 1000)

Kotlin
runOnUiThread from a Fragment
Timer
example:
Timer().schedule(500) {
activity?.runOnUiThread {
// code
}
}

A suitable solution in android:
private static long SLEEP_TIME = 2 // for 2 second
.
.
MyLauncher launcher = new MyLauncher();
launcher.start();
.
.
private class MyLauncher extends Thread {
#Override
/**
* Sleep for 2 seconds as you can also change SLEEP_TIME 2 to any.
*/
public void run() {
try {
// Sleeping
Thread.sleep(SLEEP_TIME * 1000);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
//do something you want to do
//And your code will be executed after 2 second
}
}

Related

Why I am getting an exception while inserting in database using Room library? [duplicate]

What does the following exception mean; how can I fix it?
This is the code:
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
This is the exception:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.widget.Toast.<init>(Toast.java:68)
at android.widget.Toast.makeText(Toast.java:231)
You need to call Toast.makeText(...) from the UI thread:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
This is copy-pasted from another (duplicate) SO answer.
You're calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler, for example.
Look up Communicating with the UI Thread in the documentation. In a nutshell:
// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
// This is where you do your work in the UI thread.
// Your worker tells you in the message what to do.
}
};
void workerThread() {
// And this is how you call it from the worker thread:
Message message = mHandler.obtainMessage(command, parameter);
message.sendToTarget();
}
Other options:
You could use Activity.runOnUiThread(). Straightforward if you have an Activity:
#WorkerThread
void workerThread() {
myActivity.runOnUiThread(() -> {
// This is where your UI code goes.
}
}
You could also post to the main looper. This works great if all you have is a Context.
#WorkerThread
void workerThread() {
ContextCompat.getMainExecutor(context).execute(() -> {
// This is where your UI code goes.
}
}
Deprecated:
You could use an AsyncTask, that works well for most things running in the background. It has hooks that you can call to indicate the progress, and when it's done.
It's convenient, but can leak contexts if not used correctly. It's been officially deprecated, and you shouldn't use it anymore.
UPDATE - 2016
The best alternative is to use RxAndroid (specific bindings for RxJava) for the P in MVP to take charge fo data.
Start by returning Observable from your existing method.
private Observable<PojoObject> getObservableItems() {
return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {
subscriber.onNext(pojoObject);
}
subscriber.onCompleted();
});
}
Use this Observable like this -
getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
#Override
public void onCompleted() {
// Print Toast on completion
}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(PojoObject pojoObject) {
// Show Progress
}
});
}
----------------------------------------------------------------------------------------------------------------------------------
I know I am a little late but here goes.
Android basically works on two thread types namely UI thread and background thread. According to android documentation -
Do not access the Android UI toolkit from outside the UI thread to fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Now there are various methods to solve this problem.
I will explain it by code sample:
runOnUiThread
new Thread()
{
public void run()
{
myactivity.this.runOnUiThread(new Runnable()
{
public void run()
{
//Do your UI operations like dialog opening or Toast here
}
});
}
}.start();
LOOPER
Class used to run a message loop for a thread. Threads by default do
not have a message loop associated with them; to create one, call
prepare() in the thread that is to run the loop, and then loop() to
have it process messages until the loop is stopped.
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();
}
}
AsyncTask
AsyncTask allows you to perform asynchronous work on your user
interface. It performs the blocking operations in a worker thread and
then publishes the results on the UI thread, without requiring you to
handle threads and/or handlers yourself.
public void onClick(View v) {
new CustomTask().execute((Void[])null);
}
private class CustomTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
//Do some work
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
}
Handler
A Handler allows you to send and process Message and Runnable objects
associated with a thread's MessageQueue.
Message msg = new Message();
new Thread()
{
public void run()
{
msg.arg1=1;
handler.sendMessage(msg);
}
}.start();
Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
if(msg.arg1==1)
{
//Print Toast or open dialog
}
return false;
}
});
Toast.makeText() can only be called from Main/UI thread. Looper.getMainLooper() helps you to achieve it:
JAVA
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// write your code here
}
});
KOTLIN
Handler(Looper.getMainLooper()).post {
// write your code here
}
An advantage of this method is that you can run UI code without Activity or Context.
Try this, when you see runtimeException due to Looper not prepared before handler.
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Run your task here
}
}, 1000 );
I ran into the same problem, and here is how I fixed it:
private final class UIHandler extends Handler
{
public static final int DISPLAY_UI_TOAST = 0;
public static final int DISPLAY_UI_DIALOG = 1;
public UIHandler(Looper looper)
{
super(looper);
}
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case UIHandler.DISPLAY_UI_TOAST:
{
Context context = getApplicationContext();
Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
t.show();
}
case UIHandler.DISPLAY_UI_DIALOG:
//TBD
default:
break;
}
}
}
protected void handleUIRequest(String message)
{
Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
msg.obj = message;
uiHandler.sendMessage(msg);
}
To create the UIHandler, you'll need to perform the following:
HandlerThread uiThread = new HandlerThread("UIHandler");
uiThread.start();
uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());
Hope this helps.
Reason for an error:
Worker threads are meant for doing background tasks and you can't show anything on UI within a worker thread unless you call method like runOnUiThread. If you try to show anything on UI thread without calling runOnUiThread, there will be a java.lang.RuntimeException.
So, if you are in an activity but calling Toast.makeText() from worker thread, do this:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
The above code ensures that you are showing the Toast message in a UI thread since you are calling it inside runOnUiThread method. So no more java.lang.RuntimeException.
that's what i did.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast(...);
}
});
Visual components are "locked" to changes from outside threads.
So, since the toast shows stuff on the main screen that is managed by the main thread, you need to run this code on that thread.
Hope that helps:)
I was getting this error until I did the following.
public void somethingHappened(final Context context)
{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
new Runnable()
{
#Override
public void run()
{
Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
}
}
);
}
And made this into a singleton class:
public enum Toaster {
INSTANCE;
private final Handler handler = new Handler(Looper.getMainLooper());
public void postMessage(final String message) {
handler.post(
new Runnable() {
#Override
public void run() {
Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
.show();
}
}
);
}
}
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
Wonderful Kotlin solution:
runOnUiThread {
// Add your ui thread code here
}
first call Looper.prepare() and then call Toast.makeText().show() last call Looper.loop() like:
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
This is because Toast.makeText() is calling from a worker thread. It should be call from main UI thread like this
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
The answer by ChicoBird worked for me. The only change I made was in the creation of the UIHandler where I had to do
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse refused to accept anything else. Makes sense I suppose.
Also the uiHandler is clearly a class global defined somewhere. I still don't claim to understand how Android is doing this and what is going on but I am glad it works. Now I will proceed to study it and see if I can understand what Android is doing and why one has to go through all these hoops and loops. Thanks for the help ChicoBird.
For Rxjava and RxAndroid User:
public static void shortToast(String msg) {
Observable.just(msg)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
});
}
Coroutine will do it perfectly
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
I was running into the same issue when my callbacks would try to show a dialog.
I solved it with dedicated methods in the Activity - at the Activity instance member level - that use runOnUiThread(..)
public void showAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
}
});
}
public void dismissAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
return;
}
mAuthProgressDialog.dismiss();
}
});
}
Java 8
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
});
Kotlin
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
GL
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
Now handler2 will use a different Thread to handle the messages than the main Thread.
To display a dialog or a toaster in a thread, the most concise way is to use the Activity object.
For example:
new Thread(new Runnable() {
#Override
public void run() {
myActivity.runOnUiThread(new Runnable() {
public void run() {
myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
myActivity.this.processingWaitDialog.setMessage("abc");
myActivity.this.processingWaitDialog.setIndeterminate(true);
myActivity.this.processingWaitDialog.show();
}
});
expenseClassify.serverPost(
new AsyncOperationCallback() {
public void operationCompleted(Object sender) {
myActivity.runOnUiThread(new Runnable() {
public void run() {
if (myActivity.this.processingWaitDialog != null
&& myActivity.this.processingWaitDialog.isShowing()) {
myActivity.this.processingWaitDialog.dismiss();
myActivity.this.processingWaitDialog = null;
}
}
}); // .runOnUiThread(new Runnable()
...
Using lambda:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
Toast, AlertDialogs needs to run on UI thread, you can use Asynctask to use them properly in android development.but some cases we need to customize the time outs, so we use Threads, but in threads we cannot use Toast,Alertdialogs like we using in AsyncTask.So we need separate Handler for popup those.
public void onSigned() {
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(3000);
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
} catch (Exception e){
e.printStackTrace();
}
}
};
thread.start();
}
in Above example i want to sleep my thread in 3sec and after i want to show a Toast message,for that in your mainthread implement handler.
handler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
break;
}
super.handleMessage(msg);
}
};
I used switch case here, because if you need to show different message in same way, you can use switch case within Handler class...hope this will help you
This usually happens when something on the main thread is called from any background thread. Lets look at an example , for instance.
private class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
In the above example , we are setting text on the textview which is in the main UI thread from doInBackground() method , which operates only on a worker thread.
I had the same problem and I fixed it simply by putting the Toast in onPostExecute() override function of the Asynctask<> and it worked.
You need to create toast on UI thread. Find the example below.
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
For displaying Toast message please refer to this article
Here is the solution for Kotlin using Coroutine:
Extend your class with CoroutineScope by MainScope():
class BootstrapActivity : CoroutineScope by MainScope() {}
Then simply do this:
launch {
// whatever you want to do in the main thread
}
Don't forget to add the dependencies for coroutine:
org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}
Create Handler outside the Thread
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try{
handler.post(new Runnable() {
#Override
public void run() {
showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
}
});
}
}
catch (Exception e){
Log.d("ProvidersNullExp", e.getMessage());
}
}
}).start();
Recently, I encounter this problem - It was happening because I was trying to call a function that was to do some UI stuff from the constructor. Removing the initialization from the constructor solved the problem for me.
I got the same problem and this code is working fine for me now.
As an example this is my code to do a task in the background and UI thread.
Observe how the looper is used:
new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
// your Background Task here
runOnUiThread(new Runnable() {
#Override
public void run() {
// update your UI here
Looper.loop();
}
});
}
}).start();
i use the following code to show message from non main thread "context",
#FunctionalInterface
public interface IShowMessage {
Context getContext();
default void showMessage(String message) {
final Thread mThread = new Thread() {
#Override
public void run() {
try {
Looper.prepare();
Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception error) {
error.printStackTrace();
Log.e("IShowMessage", error.getMessage());
}
}
};
mThread.start();
}
}
then use as the following:
class myClass implements IShowMessage{
showMessage("your message!");
#Override
public Context getContext() {
return getApplicationContext();
}
}

onClick() setting incrementation and delay

I'm new to Android and I'm working on a tiny project with a set of strict parameters. One of them is to have a multifunction button that increments a timer every time it's clicked, and that starts only after I didn't increment said timer for 3 seconds.
I found three or four ways on how to set an alarm of sorts with Handler, CountDownTimer, Timer, or some other way, but I'm confused on how I can do what I'm looking for with just the onClick() method.
The function to wait for 3s(), I'm calling it after:
public void wait3s()
{
Thread thread = new Thread() {
#Override
public void run()
{
while (!isInterrupted()) {
try {
Thread.sleep(3000);
runOnUiThread(new Runnable() {
#Override
public void run() {
count++;
threeS.setText(String.valueOf(count));
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
}
My onClick() just calls these:
public void onClick(View view)
{
increment();
wait3s();
startStop();
}
As you can see, part of the issue is that I'm calling the wait3s() there at every click, and I need a way to control that Thread/Timer (whatever) without it creating a new one at every click. I'm being a little dumb now, but I have been on this for a while and I'm still coming out empty, since I never worked with this before.
Another option for the wait3s() function that I found would be like in this other StackOverflow thread.
Thank you
PS: Sorry for the title, I couldn't find a better way to describe it, if you have it, and have the power to change it, please do.
Handler.removeCallbacks will effectively cancel a runnable.
boolean timerStarted = false;
clockHandler = new Handler();
OnClick(){
if (!timerStarted){
incrementTimer();
clockHandler.removeCallbacks(null);
clockHandler.postDelayed(new Runnable() {
#Override
public void run() {
// maybe kick off another handler/runnable here to start your timer
timerStarted = true;
}
}
}, 3 * 60 * 1000);
} else {
startStop();
}
}
Here's how I solve it. Although the suggestions were closer, they weren't exactly spot on to what I was looking for, in terms of logic, they weren't exactly helpful, creating more issues. Perhaps it's due to my explanation of the problem, perhaps because I'm new to Android Studio and the explanations shared here with me. Pardon me if it looks like I'm just using my own answer for internet points, I just had to put a lot more to understand this by myself than what I actually got from the answers shared here.
public void wait3s()
{
t.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
startStop();
}
});
}
}, 3000);
}
The variable t is a Timer(), and I had to import the classes java.util.Timer, and java.util.TimerTask. I called this method inside my increment() method and under onClick() I just have the increment() method. Turned out pretty neat.

Toast in the beginning of a thread [duplicate]

What does the following exception mean; how can I fix it?
This is the code:
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
This is the exception:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.widget.Toast.<init>(Toast.java:68)
at android.widget.Toast.makeText(Toast.java:231)
You need to call Toast.makeText(...) from the UI thread:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
This is copy-pasted from another (duplicate) SO answer.
You're calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler, for example.
Look up Communicating with the UI Thread in the documentation. In a nutshell:
// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
// This is where you do your work in the UI thread.
// Your worker tells you in the message what to do.
}
};
void workerThread() {
// And this is how you call it from the worker thread:
Message message = mHandler.obtainMessage(command, parameter);
message.sendToTarget();
}
Other options:
You could use Activity.runOnUiThread(). Straightforward if you have an Activity:
#WorkerThread
void workerThread() {
myActivity.runOnUiThread(() -> {
// This is where your UI code goes.
}
}
You could also post to the main looper. This works great if all you have is a Context.
#WorkerThread
void workerThread() {
ContextCompat.getMainExecutor(context).execute(() -> {
// This is where your UI code goes.
}
}
Deprecated:
You could use an AsyncTask, that works well for most things running in the background. It has hooks that you can call to indicate the progress, and when it's done.
It's convenient, but can leak contexts if not used correctly. It's been officially deprecated, and you shouldn't use it anymore.
UPDATE - 2016
The best alternative is to use RxAndroid (specific bindings for RxJava) for the P in MVP to take charge fo data.
Start by returning Observable from your existing method.
private Observable<PojoObject> getObservableItems() {
return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {
subscriber.onNext(pojoObject);
}
subscriber.onCompleted();
});
}
Use this Observable like this -
getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
#Override
public void onCompleted() {
// Print Toast on completion
}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(PojoObject pojoObject) {
// Show Progress
}
});
}
----------------------------------------------------------------------------------------------------------------------------------
I know I am a little late but here goes.
Android basically works on two thread types namely UI thread and background thread. According to android documentation -
Do not access the Android UI toolkit from outside the UI thread to fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Now there are various methods to solve this problem.
I will explain it by code sample:
runOnUiThread
new Thread()
{
public void run()
{
myactivity.this.runOnUiThread(new Runnable()
{
public void run()
{
//Do your UI operations like dialog opening or Toast here
}
});
}
}.start();
LOOPER
Class used to run a message loop for a thread. Threads by default do
not have a message loop associated with them; to create one, call
prepare() in the thread that is to run the loop, and then loop() to
have it process messages until the loop is stopped.
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();
}
}
AsyncTask
AsyncTask allows you to perform asynchronous work on your user
interface. It performs the blocking operations in a worker thread and
then publishes the results on the UI thread, without requiring you to
handle threads and/or handlers yourself.
public void onClick(View v) {
new CustomTask().execute((Void[])null);
}
private class CustomTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
//Do some work
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
}
Handler
A Handler allows you to send and process Message and Runnable objects
associated with a thread's MessageQueue.
Message msg = new Message();
new Thread()
{
public void run()
{
msg.arg1=1;
handler.sendMessage(msg);
}
}.start();
Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
if(msg.arg1==1)
{
//Print Toast or open dialog
}
return false;
}
});
Toast.makeText() can only be called from Main/UI thread. Looper.getMainLooper() helps you to achieve it:
JAVA
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// write your code here
}
});
KOTLIN
Handler(Looper.getMainLooper()).post {
// write your code here
}
An advantage of this method is that you can run UI code without Activity or Context.
Try this, when you see runtimeException due to Looper not prepared before handler.
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Run your task here
}
}, 1000 );
I ran into the same problem, and here is how I fixed it:
private final class UIHandler extends Handler
{
public static final int DISPLAY_UI_TOAST = 0;
public static final int DISPLAY_UI_DIALOG = 1;
public UIHandler(Looper looper)
{
super(looper);
}
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case UIHandler.DISPLAY_UI_TOAST:
{
Context context = getApplicationContext();
Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
t.show();
}
case UIHandler.DISPLAY_UI_DIALOG:
//TBD
default:
break;
}
}
}
protected void handleUIRequest(String message)
{
Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
msg.obj = message;
uiHandler.sendMessage(msg);
}
To create the UIHandler, you'll need to perform the following:
HandlerThread uiThread = new HandlerThread("UIHandler");
uiThread.start();
uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());
Hope this helps.
Reason for an error:
Worker threads are meant for doing background tasks and you can't show anything on UI within a worker thread unless you call method like runOnUiThread. If you try to show anything on UI thread without calling runOnUiThread, there will be a java.lang.RuntimeException.
So, if you are in an activity but calling Toast.makeText() from worker thread, do this:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
The above code ensures that you are showing the Toast message in a UI thread since you are calling it inside runOnUiThread method. So no more java.lang.RuntimeException.
that's what i did.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast(...);
}
});
Visual components are "locked" to changes from outside threads.
So, since the toast shows stuff on the main screen that is managed by the main thread, you need to run this code on that thread.
Hope that helps:)
I was getting this error until I did the following.
public void somethingHappened(final Context context)
{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
new Runnable()
{
#Override
public void run()
{
Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
}
}
);
}
And made this into a singleton class:
public enum Toaster {
INSTANCE;
private final Handler handler = new Handler(Looper.getMainLooper());
public void postMessage(final String message) {
handler.post(
new Runnable() {
#Override
public void run() {
Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
.show();
}
}
);
}
}
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
Wonderful Kotlin solution:
runOnUiThread {
// Add your ui thread code here
}
first call Looper.prepare() and then call Toast.makeText().show() last call Looper.loop() like:
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
This is because Toast.makeText() is calling from a worker thread. It should be call from main UI thread like this
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
The answer by ChicoBird worked for me. The only change I made was in the creation of the UIHandler where I had to do
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse refused to accept anything else. Makes sense I suppose.
Also the uiHandler is clearly a class global defined somewhere. I still don't claim to understand how Android is doing this and what is going on but I am glad it works. Now I will proceed to study it and see if I can understand what Android is doing and why one has to go through all these hoops and loops. Thanks for the help ChicoBird.
For Rxjava and RxAndroid User:
public static void shortToast(String msg) {
Observable.just(msg)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
});
}
Coroutine will do it perfectly
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
I was running into the same issue when my callbacks would try to show a dialog.
I solved it with dedicated methods in the Activity - at the Activity instance member level - that use runOnUiThread(..)
public void showAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
}
});
}
public void dismissAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
return;
}
mAuthProgressDialog.dismiss();
}
});
}
Java 8
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
});
Kotlin
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
GL
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
Now handler2 will use a different Thread to handle the messages than the main Thread.
To display a dialog or a toaster in a thread, the most concise way is to use the Activity object.
For example:
new Thread(new Runnable() {
#Override
public void run() {
myActivity.runOnUiThread(new Runnable() {
public void run() {
myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
myActivity.this.processingWaitDialog.setMessage("abc");
myActivity.this.processingWaitDialog.setIndeterminate(true);
myActivity.this.processingWaitDialog.show();
}
});
expenseClassify.serverPost(
new AsyncOperationCallback() {
public void operationCompleted(Object sender) {
myActivity.runOnUiThread(new Runnable() {
public void run() {
if (myActivity.this.processingWaitDialog != null
&& myActivity.this.processingWaitDialog.isShowing()) {
myActivity.this.processingWaitDialog.dismiss();
myActivity.this.processingWaitDialog = null;
}
}
}); // .runOnUiThread(new Runnable()
...
Using lambda:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
Toast, AlertDialogs needs to run on UI thread, you can use Asynctask to use them properly in android development.but some cases we need to customize the time outs, so we use Threads, but in threads we cannot use Toast,Alertdialogs like we using in AsyncTask.So we need separate Handler for popup those.
public void onSigned() {
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(3000);
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
} catch (Exception e){
e.printStackTrace();
}
}
};
thread.start();
}
in Above example i want to sleep my thread in 3sec and after i want to show a Toast message,for that in your mainthread implement handler.
handler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
break;
}
super.handleMessage(msg);
}
};
I used switch case here, because if you need to show different message in same way, you can use switch case within Handler class...hope this will help you
This usually happens when something on the main thread is called from any background thread. Lets look at an example , for instance.
private class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
In the above example , we are setting text on the textview which is in the main UI thread from doInBackground() method , which operates only on a worker thread.
I had the same problem and I fixed it simply by putting the Toast in onPostExecute() override function of the Asynctask<> and it worked.
You need to create toast on UI thread. Find the example below.
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
For displaying Toast message please refer to this article
Here is the solution for Kotlin using Coroutine:
Extend your class with CoroutineScope by MainScope():
class BootstrapActivity : CoroutineScope by MainScope() {}
Then simply do this:
launch {
// whatever you want to do in the main thread
}
Don't forget to add the dependencies for coroutine:
org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}
Create Handler outside the Thread
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try{
handler.post(new Runnable() {
#Override
public void run() {
showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
}
});
}
}
catch (Exception e){
Log.d("ProvidersNullExp", e.getMessage());
}
}
}).start();
Recently, I encounter this problem - It was happening because I was trying to call a function that was to do some UI stuff from the constructor. Removing the initialization from the constructor solved the problem for me.
I got the same problem and this code is working fine for me now.
As an example this is my code to do a task in the background and UI thread.
Observe how the looper is used:
new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
// your Background Task here
runOnUiThread(new Runnable() {
#Override
public void run() {
// update your UI here
Looper.loop();
}
});
}
}).start();
i use the following code to show message from non main thread "context",
#FunctionalInterface
public interface IShowMessage {
Context getContext();
default void showMessage(String message) {
final Thread mThread = new Thread() {
#Override
public void run() {
try {
Looper.prepare();
Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception error) {
error.printStackTrace();
Log.e("IShowMessage", error.getMessage());
}
}
};
mThread.start();
}
}
then use as the following:
class myClass implements IShowMessage{
showMessage("your message!");
#Override
public Context getContext() {
return getApplicationContext();
}
}

Android: runOnUiThread does not always choose the right thread?

I've got an activity that keeps reading words to the user, and using onUtteranceCompleted with textTospeech to display something when the code is completed.
Inside onUtteranceCompleted I have this code to delay a function with a second:
Runnable task = new Runnable() {
public void run() {
//runs on ui
runOnUiThread(new Runnable() {
public void run() {
readWord();
}
});
}
};
worker.schedule(task, 1, TimeUnit.SECONDS);
This seems like it works well, but I think it is causing a problem.
When I rotate the screen of my phone (I guess this starts a new activity).
I hear some words being read in the background. I guess this is because of runOnUiThread() which makes the activity continue in the background.
How could I avoid 2 activities running ? I would prefer if I don't have to stop the screen from rotating on doing some weird patch!
Thank you
EDIT:
public void readWord() {
if (this.readingOnPause) {
return;
}
txtCurrentWord.setText(currentItem[1]);
this.hashAudio.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"word");
this.tts.setLanguage(Locale.US);
this.tts.speak(this.currentItem[1], TextToSpeech.QUEUE_FLUSH,this.hashAudio);
}
EDIT2:
instantiation of worker:
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
I would use a Handler instead of runOnUiThread().
For one thing, you're using a Thread that starts another Thread - why?
Secondly, if you create a simple Handler, it should kill itself on the rotate config change. IE:
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do your background or UI stuff
}
};
Then later use a Thread to call the handler, which will kick off whatever process you want to run on the UI thread:
new Thread() {
#Override
public void run() {
long timestamp = System.currentTimeMillis();
// thread blocks for your 1 second delay
while (System.currentTimeMillis() - timestamp <= 1000) {
// loop
}
handler.sendEmptyMessage(0);
}
}.start();
Ok so this is a fix I've come up with, if someone has a better solution, I'm listening.
I've added android:configChanges="keyboardHidden|orientation" inside the activity in the androidmanifest
2.
and then a function that is called when the screen is rotate:
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
setContentView(R.layout.streaming);
initializeUI(); //contains all the findViewByID etc...
}

Android timer/timertask causing my app to crash?

Just testing out a simple block of code in my mainActivity's onCreate:
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
};
timer2.schedule(testing, 1000);
I get the "force close" error though.
What gives?
Alright for anyone else who runs into this, I fixed the problem by using a Handler and Runnable to do the Toast, which seems to be needed for UI interaction:
final Handler handler = new Handler();
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
});
}
};
timer2.schedule(testing, 1000);
I still don't understand why this is necessary though, perhaps someone could explain? But hey at least this code works lol.
Timer(Tasks) are bad! Do it the Android way: Use a Handler.
As you can see in the code snippet, it’s pretty easy to go that way too:
First we need a Handler that starts the Runnable after 100ms
private Handler handler = new Handler();
handler.postDelayed(runnable, 100);
And we also need the Runnable for the Handler
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* do what you need to do */
foobar();
/* and here comes the "trick" */
handler.postDelayed(this, 100);
}
};
So the “trick” is to tell the handler at the end to start the Runnable again. This way the runnable is started every 100ms, like a scheduleAtFixedRate() TimerTask! If you want it to stop, you can just call handler.removeCallback(runnable) and it won’t start again, until you tell it to
This exact issue is discussed in this article:
http://developer.android.com/resources/articles/timed-ui-updates.html
The app crashes because you are attempting to access elements of the UI thread (a toast) from a different thread (the timer thread). You cannot do this!
You can get round it by either:
Sending a handler message from the timer thread to the UI thread, and then showing the toast in the UI handler function.
OR
In the timer code run use 'runOnUiThread':
#Override
public void run()
{
mainActivity.runOnUiThread(new Runnable() {
public void run() {
// Access/update UI here
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
});
}
#YoungMoney
It works but only the first time... Did you make it display the Toast message every second??
Mine only worked once...
===
Edit:
Just realised your last line of code is missing the last value which is how often to repeat.
For anyone else concerned, change this:
timer2.schedule(testing, 1000);
to this:
timer2.schedule(testing, 1000, 2000);
If you want to start the timer in 1 second, and update every 2 seconds.
TimerTask task = new TimerTask() {
#Override
public void run() {
//do something
}
};
Timer t = new Timer();
t.schedule(task, 2000);

Categories

Resources