How do I fix the deprecation warning in this code? Alternatively, are there any other options for doing this?
Handler().postDelayed({
context?.let {
//code
}
}, 3000)
Only the parameterless constructor is deprecated, it is now preferred that you specify the Looper in the constructor via the Looper.getMainLooper() method.
Use it for Java
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
// Your Code
}
}, 3000);
Use it for Kotlin
Handler(Looper.getMainLooper()).postDelayed({
// Your Code
}, 3000)
Source : developer.android.com
From API level 30, there are 2 constructors are deprecated.
Handler()
Handler(Handler.Callback)
Google explains the reason below.
Implicitly choosing a Looper during
Handler construction can lead to bugs where operations are silently
lost (if the Handler is not expecting new tasks and quits), crashes
(if a handler is sometimes created on a thread without a Looper
active), or race conditions, where the thread a handler is associated
with is not what the author anticipated. Instead, use an Executor or
specify the Looper explicitly, using Looper#getMainLooper, {link
android.view.View#getHandler}, or similar. If the implicit thread
local behavior is required for compatibility, use new
Handler(Looper.myLooper(), callback) to make it clear to readers.
Solution 1: Use an Executor
1. Execute code in the main thread.
Java
// Create an executor that executes tasks in the main thread.
Executor mainExecutor = ContextCompat.getMainExecutor(this);
// Execute a task in the main thread
mainExecutor.execute(new Runnable() {
#Override
public void run() {
// You code logic goes here.
}
});
Kotlin
// Create an executor that executes tasks in the main thread.
val mainExecutor = ContextCompat.getMainExecutor(this)
// Execute a task in the main thread
mainExecutor.execute {
// You code logic goes here.
}
2. Execute code in a background thread
Java
// Create an executor that executes tasks in a background thread.
ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
// Execute a task in the background thread.
backgroundExecutor.execute(new Runnable() {
#Override
public void run() {
// Your code logic goes here.
}
});
// Execute a task in the background thread after 3 seconds.
backgroundExecutor.schedule(new Runnable() {
#Override
public void run() {
// Your code logic goes here
}
}, 3, TimeUnit.SECONDS);
Kotlin
// Create an executor that executes tasks in a background thread.
val backgroundExecutor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
// Execute a task in the background thread.
backgroundExecutor.execute {
// Your code logic goes here.
}
// Execute a task in the background thread after 3 seconds.
backgroundExecutor.schedule({
// Your code logic goes here
}, 3, TimeUnit.SECONDS)
Note: Remember to shut down the executor after using.
backgroundExecutor.shutdown(); // or backgroundExecutor.shutdownNow();
3. Execute code in a background thread and update UI on the main thread.
Java
// Create an executor that executes tasks in the main thread.
Executor mainExecutor = ContextCompat.getMainExecutor(this);
// Create an executor that executes tasks in a background thread.
ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
// Execute a task in the background thread.
backgroundExecutor.execute(new Runnable() {
#Override
public void run() {
// Your code logic goes here.
// Update UI on the main thread
mainExecutor.execute(new Runnable() {
#Override
public void run() {
// You code logic goes here.
}
});
}
});
Kotlin
// Create an executor that executes tasks in the main thread.
val mainExecutor: Executor = ContextCompat.getMainExecutor(this)
// Create an executor that executes tasks in a background thread.
val backgroundExecutor = Executors.newSingleThreadScheduledExecutor()
// Execute a task in the background thread.
backgroundExecutor.execute {
// Your code logic goes here.
// Update UI on the main thread
mainExecutor.execute {
// You code logic goes here.
}
}
Solution 2: Specify a Looper explicitly by using one of the following constructors.
Handler(Looper)
Handler(Looper, Handler.Callback)
1. Execute code in the main thread
1.1. Handler with a Looper
Java
Handler mainHandler = new Handler(Looper.getMainLooper());
Kotlin
val mainHandler = Handler(Looper.getMainLooper())
1.2 Handler with a Looper and a Handler.Callback
Java
Handler mainHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(#NonNull Message message) {
// Your code logic goes here.
return true;
}
});
Kotlin
val mainHandler = Handler(Looper.getMainLooper(), Handler.Callback {
// Your code logic goes here.
true
})
2. Execute code in a background thread
2.1. Handler with a Looper
Java
// Create a background thread that has a Looper
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
// Create a handler to execute tasks in the background thread.
Handler backgroundHandler = new Handler(handlerThread.getLooper());
Kotlin
// Create a background thread that has a Looper
val handlerThread = HandlerThread("HandlerThread")
handlerThread.start()
// Create a handler to execute tasks in the background thread.
val backgroundHandler = Handler(handlerThread.looper)
2.2. Handler with a Looper and a Handler.Callback
Java
// Create a background thread that has a Looper
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
// Create a handler to execute taks in the background thread.
Handler backgroundHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(#NonNull Message message) {
// Your code logic goes here.
return true;
}
});
Kotlin
// Create a background thread that has a Looper
val handlerThread = HandlerThread("HandlerThread")
handlerThread.start()
// Create a handler to execute taks in the background thread.
val backgroundHandler = Handler(handlerThread.looper, Handler.Callback {
// Your code logic goes here.
true
})
Note: Remember to release the thread after using.
handlerThread.quit(); // or handlerThread.quitSafely();
3. Execute code in a background thread and update UI on the main thread.
Java
// Create a handler to execute code in the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());
// Create a background thread that has a Looper
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
// Create a handler to execute in the background thread
Handler backgroundHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(#NonNull Message message) {
// Your code logic goes here.
// Update UI on the main thread.
mainHandler.post(new Runnable() {
#Override
public void run() {
}
});
return true;
}
});
Kotlin
// Create a handler to execute code in the main thread
val mainHandler = Handler(Looper.getMainLooper())
// Create a background thread that has a Looper
val handlerThread = HandlerThread("HandlerThread")
handlerThread.start()
// Create a handler to execute in the background thread
val backgroundHandler = Handler(handlerThread.looper, Handler.Callback {
// Your code logic goes here.
// Update UI on the main thread.
mainHandler.post {
}
true
})
If you want to avoid the null check thing in Kotlin (? or !!) you can use Looper.getMainLooper() if your Handler is working with some UI related thing, like this:
Handler(Looper.getMainLooper()).postDelayed({
Toast.makeText(this#MainActivity, "LOOPER", Toast.LENGTH_SHORT).show()
}, 3000)
Note: use requireContext() instead of this#MainActivity if you are using fragment.
The deprecated function is that constructor for Handler. Use Handler(Looper.myLooper()) .postDelayed(runnable, delay) instead
Consider using coroutines
scope.launch {
delay(3000L)
// do stuff
}
Using lifecycle scope this is more easy. Inside activity or fragment.
lifecycleScope.launch {
delay(2000)
// Do your stuff
}
or use handler
Handler(Looper.myLooper()!!)
I have 3 solutions:
Specify the Looper explicitly:
Handler(Looper.getMainLooper()).postDelayed({
// code
}, duration)
Specify the implicit thread local behavior:
Handler(Looper.myLooper()!!).postDelayed({
// code
}, duration)
using Thread:
Thread({
try{
Thread.sleep(3000)
} catch (e : Exception) {
throw e
}
// code
}).start()
Handler() and Handler(Handler.Callback callback) constructors are deprecated. Because those can leads to bugs & crashes. Use Executor or Looper explicitly.
For Java
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//do your work here
}
}, 1000);
use this
Looper.myLooper()?.let {
Handler(it).postDelayed({
//Your Code
},2500)
}
Use Executor instead of handler for more info Executor.
To achieve post delay use ScheduledExecutorService:
ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = () -> {
public void run() {
// Do something
}
};
worker.schedule(runnable, 2000, TimeUnit.MILLISECONDS);
Provide a looper in the Handler Constructor
Handler(Looper.getMainLooper())
import android.os.Looper
import android.os.Handler
inline fun delay(delay: Long, crossinline completion: () -> Unit) {
Handler(Looper.getMainLooper()).postDelayed({
completion()
}, delay)
}
Example:
delay(1000) {
view.refreshButton.visibility = View.GONE
}
If you are using Variable for Handler and Runnable then use it like this.
private Handler handler;
private Runnable runnable;
handler = new Handler(Looper.getMainLooper());
handler.postDelayed(runnable = () -> {
// Do delayed stuff here
handler.postDelayed(runnable, 1000);
}, delay);
Also You need to remove callbacks in onDestroy()
#Override
public void onDestroy() {
super.onDestroy();
if (handler != null) {
handler.removeCallbacks(runnable);
}
}
Coroutines Kotlin
private val SPLASH_SCREEN_TIME_OUT_CONST: Long = 3000
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
GlobalScope.launch {
delay(SPLASH_SCREEN_TIME_OUT_CONST)
goToIntro()
}
}
private fun goToIntro(){
startActivity(Intent(this, IntroActivity::class.java))
finish()
}
It's a good idea use this structure in Kotlin
companion object Run {
fun after(delay: Long, process: () -> Unit) {
Handler(Looper.getMainLooper()).postDelayed({
process()
}, delay)
}
}
Later call as
Run.after(SPLASH_TIME_OUT) {
val action = SplashFragmentDirections.actionSplashFragmentToLogin()
v.findNavController().navigate(action)
}
Java Answer
I wrote a method to use easily. You can use this method directly in your project. delayTimeMillis can be 2000, it means that this code will run after 2 seconds.
private void runJobWithDelay(int delayTimeMillis){
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
//todo: you can call your method what you want.
}
}, delayTimeMillis);
}
According to the document (https://developer.android.com/reference/android/os/Handler#Handler()):
Implicitly choosing a Looper during Handler construction can lead to bugs where operations are silently lost (if the Handler is not expecting new tasks and quits), crashes (if a handler is sometimes created on a thread without a Looper active), or race conditions, where the thread a handler is associated with is not what the author anticipated. Instead, use an Executor or specify the Looper explicitly, using Looper#getMainLooper, {link android.view.View#getHandler}, or similar. If the implicit thread local behavior is required for compatibility, use new Handler(Looper.myLooper()) to make it clear to readers.
We should stop using the constructor without a Looper, and specify a Looper instead.
I usually use this one
Code:
Handler(Looper.myLooper() ?: return).postDelayed({
// Code what do you want
}, 3000)
Screenshot:
The handler() etc code is generated by the Android Studio 4.0.1 when a Fullscreen Activity, for example, is created from scratch. I know that we are being encouraged to use Kotlin, which I do, but from time to time I use sample projects to get an idea going.
It seems strange that we are chastised by AS when AS actually generates the code. It might be a useful academic activity to go through the errors and fix them but maybe AS could generate new clean code for us enthusiasts...
For Xamarin Android, instead of
Handler handler;
handler = new Handler();
just write
Handler handler;
handler = new Handler(Looper.MyLooper());
the rest of the code is fine.
i want to send a Broadcast from a FromTowerThread with the following method:
void postToService(final String string){
Handler handler = new Handler();
handler.post(new Runnable(){
#Override
public void run() {
context.sendBroadcast(new Intent(string));
}
});
}
My context is 'this' (my service):
FromTowerThread ftt = new FromTowerThread(this);
(just for completeness my constructor in FromTowerThread):
public FromTowerThread(Context context){
this.context=context;
}
The Error i get is "Can't create handler inside thread that has not called Looper.prepare()".
I don't know how to fix this error, all threads i found about this topic could not help me to understand this.
Thanks in advance!
Chris
change the statement
Handler handler = new Handler();
to
Handler handler = new Handler(Looper.getMainLooper());
Post can only be done from a Handler in a thread that called Looper.prepare().
I'm assuming here that the thread that calls void postToService(final String string) is some type of background thread. Usually the UI thread does call Looper.prepare() meaning that you would have to create the Handler inside the UI thread.
but just as a general suggestion, I'm pretty sure you can just eliminate all of this and just call the broadcast straight away:
void postToService(final String string){
context.sendBroadcast(new Intent(string));
}
The Error i get is "Can't create handler inside thread that has not called Looper.prepare()".
If you are extending Thread, try extending HandlerThread instead. A HandlerThread has a Looper already. (Or you can call Looper.prepare() and Looper.loop() yourself in a regular Thread.)
Otherwise you can do a few things to use the main Thread's Looper. For instance create the Handler in the main Thread and pass it to your worker Thread or even pass a View from the UI Thread and call view.post(Runnable) to execute that Runnable on the UI Thread.
I am trying to understand how looper.loop works, and when to use it in my code.
I have a bound service that has a runnable. Inside I have a handler that is used to hold code that updates the Ui. Here is the code.
private Runnable builder = new Runnable() {
public void run()
{
while(isThreadStarted == true)
{
if (newgps == 1)
{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
//some code that updates UI
}
}
}
}
}
looper.prepair
}
From what I read looper. prepare has to be called before the handler is made. But I noticed I didn’t do that but this code still works. How is this possible?
I want to fix this but im not sure where to put loper.loop. Because this handler is called many many times. Would it be ok if i put looper.loop right after .prepare? Then .quit when isThreadStarted == false?
The Handler is associated with the UI thread, since you attach it to Looper.getMainLooper(). The UI thread prepares its Looperon application start, so that is nothing the application has to do itself.
By using Looper.getMainLooper(), you get Handler of main thread and you are posting on main thread. Main thread has its looper prepared by system already when it is created.
I just solved the problem myself. I had multiple calls for syncCustomers() due to a dialog closing event problem. I solved it by providing the parent JFrame in the JDialog constructor. Pretty stupid error on my side.
My application contains a task that synchronizes with a webservice and a local database. This task may take up to several minutes. Thus I want to notify the user about this time consuming process with a simple dialog (Swing). The user is not supposed to continue working while the sync process is running.
So I thought of:
open modal dialog with the notification for the user
start the sync process in a separate thread
close modal dialog after sync process is done
User clicked on the button to start sync process:
private void syncCustomers() {
if (checkWebserviceAuth()) {
SyncDialog dialog = new SyncDialog();
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
SyncCustomersTask task = new SyncCustomersTask(dialog, getCoach());
task.run(); // task.start() will result in the same problem
} else {
openAuthorizeDialog(true);
}
}
public class SyncDialog extends javax.swing.JDialog {
public SyncDialog() {
initComponents();
// I already noticed that the modal dialog won't work for me since it interrupts within syncCustomers()
//this.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
this.setTitle(Application.getApplicationTitle());
}
...
}
public class SyncCustomersTask extends Thread {
private void doWork() {
System.out.println("Start doWork() and sleep for 10 seconds...");
try {
// for testing purpose
Thread.sleep(10000);
} catch (InterruptedException ex) {
}
System.out.println("Done with doWork().");
}
#Override
public void run() {
doWork();
if (getCallback() != null) {
System.out.println("Invoke callback...");
getCallback().dispose();
System.out.println("Callback invoked.");
}
}
...
}
This will result in an infinite loop of:
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
If I comment out
getCallback().dispose();
, the loop will stop after the second execution:
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
I don't get it. What fires the thread to execute over and over again?
I guess this whole thing isn't a good idea to start with, but I wasn't able to get things like ProgressMonitor working either. :(
Call start(), not run(). The latter will simply execute the thread, but not in a separate thread! The start() method will instantiate a new thread, and only then invoke your run() method in that new thread.
This is a surprising common problem, btw.
invoking run() does not execute code in a new thread.
I have an Android service which spawns a thread.This thread waits for network data and after receiving that data I want to show Ok Cancel Dialogbox.
I was getting exception can't create handle that should have Looper.prepare().I added Looper.prepare() and Looper.loop() then now I am not getting any exception but its waiting infinitely.
Instead of using a sole thread it's better to use an AsyncTask which is also a speacialized thread for Android.
You can wait for data in the AsyncTask's doInBackGround method and when you received data you can call publishProgress() which will invoke onProgressUpdate method of AsyncTask.
At onProgressUpdate you can update the UI without blocking the main thread and also this is the preferred way of doing long time operations in background like network listening etc.
Check AsyncTask for more info and how to use it.
http://developer.android.com/reference/android/os/AsyncTask.html
You can invoke the UI thread(showing alert dialog) in non-UI thread by using handlers as like below code
new Thread(new Runnable()
{ public void run()
{
try {
///do your stuff in
mHandlerShowDialog.post(mUpdateShowDialog);
///do your struff
}
} ).start();
final Handler mHandlerShowDialog= new Handler();
final Runnable mUpdateShowDialog = new Runnable() {
public void run() {
// show your dialog here
}
};