What do I use now that Handler() is deprecated?
Asked Answered
T

20

369

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)
Tannic answered 4/4, 2020 at 4:58 Comment(1)
Just use new before the code. new Handler().postDelayed({ context?.let { //code } }, 3000)Incapacious
S
703

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

Sobriquet answered 11/9, 2020 at 17:40 Comment(3)
Straight forward...Pseudaxis
what is getMainLooper()?Westbrooks
@Westbrooks Returns the application's main looper, which lives in the main thread of the application. developer.android.com/reference/android/os/…Sobriquet
L
97

From API level 30, there are 2 constructors that are deprecated.

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.

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
})
Lat answered 1/12, 2020 at 0:21 Comment(3)
awesome stuff ! CheersFumigator
Genius!! Best AnswerEndomorphism
Hello sir, How to get message in kotlin, thank you.Lover
H
79

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.

Hoax answered 19/6, 2020 at 19:56 Comment(0)
M
29

The deprecated function is that constructor for Handler. Use Handler(Looper.myLooper()) .postDelayed(runnable, delay) instead

Miserere answered 4/4, 2020 at 7:57 Comment(2)
This doesn't work in Kotlin because Looper.myLooper() returns a Looper? (possible null value).Leprose
@EllenSpertus Then add in a null check, or use Looper.myLooper()!! which will throw an NPE if its null. If you're on a thread with a looper it will return non-null. If not, it will return null and should throw an exception in any language.Miserere
R
24

Consider using coroutines

scope.launch {
    delay(3000L)
    // do stuff
}
Roulade answered 4/4, 2020 at 6:5 Comment(1)
Inside Activity or Fragment: lifecycleScope.launch { delay(3000L) }Nitro
P
22

Using lifecycle scope this is more easy. Inside activity or fragment.

 lifecycleScope.launch {
     delay(2000)
     // Do your stuff
 }

or use handler

        Handler(Looper.myLooper()!!)
Penoyer answered 13/10, 2020 at 13:52 Comment(3)
How to avoid the !! operator ?Dissuasive
It can be null so you have to write !! to ensure it is not nullPenoyer
doing !! can cause exception as looper can be null nad Handler requires a non-nulable valueSurveying
A
18

I have 3 solutions:

  1. Specify the Looper explicitly:
    Handler(Looper.getMainLooper()).postDelayed({
        // code
    }, duration)
    
  2. Specify the implicit thread local behavior:
    Handler(Looper.myLooper()!!).postDelayed({
        // code
    }, duration)
    
  3. using Thread:
    Thread({
        try{
            Thread.sleep(3000)
        } catch (e : Exception) {
            throw e
        }
         // code
    }).start()
    
Armijo answered 13/11, 2021 at 15:5 Comment(0)
J
13

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);
Jean answered 23/7, 2021 at 2:30 Comment(0)
S
10

use this

Looper.myLooper()?.let {
    Handler(it).postDelayed({
        //Your Code
    },2500)
}
Sakti answered 13/8, 2020 at 13:36 Comment(0)
E
9

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);
Emmettemmey answered 4/4, 2020 at 5:3 Comment(1)
This is not a bad answer, in fact even google recommends this.Janson
B
8
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
}
Boggart answered 22/1, 2022 at 6:36 Comment(0)
A
7

Provide a looper in the Handler Constructor

Handler(Looper.getMainLooper())
Amberlyamberoid answered 1/10, 2020 at 13:39 Comment(0)
F
4

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);
    }
}
Feoff answered 18/1, 2021 at 13:2 Comment(0)
C
3

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.

Compromise answered 13/5, 2020 at 15:19 Comment(0)
E
3

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()
}
Essence answered 3/4, 2021 at 14:12 Comment(1)
I think there is no difference between GlobalScope vs Handler. The GlobalScope doesn't aware the lifecycle(except the app process). In my opinion, lifecycle scope or custom scope is more convenient way according to the GlobalScope.Discourtesy
A
3

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)
}
Aubergine answered 28/4, 2021 at 2:11 Comment(0)
R
2

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);
}
Raddle answered 19/10, 2020 at 9:18 Comment(0)
T
1

I usually use this one

Code:

Handler(Looper.myLooper() ?: return).postDelayed({
           // Code what do you want
        }, 3000)

Screenshot:

enter image description here

Tautog answered 29/12, 2020 at 17:14 Comment(0)
C
0

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...

Clover answered 24/8, 2020 at 4:21 Comment(0)
J
0

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.

Janessajanet answered 6/6, 2022 at 20:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.