现在Handler()被弃用了,我应该用什么?

309 人关注

我怎样才能修复这段代码中的废弃警告?另外,是否有其他的选择来做这件事?

Handler().postDelayed({
    context?.let {
        //code
}, 3000)
    
java
android
kotlin
android-handler
Bolt UIX
Bolt UIX
发布于 2020-04-04
20 个回答
Nikunj Paradva
Nikunj Paradva
发布于 2022-06-07
已采纳
0 人赞同

只有无参数的构造函数被弃用,现在更倾向于在构造函数中通过 Looper 方法指定 Looper.getMainLooper()

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)
    
直截了当...
什么是getMainLooper()?
@UNREAL 返回应用程序的主循环器,它生活在应用程序的主线程中。 developer.android.com/reference/android/os/...
Son Truong
Son Truong
发布于 2022-06-07
0 人赞同

从API级别30开始,有2个构造函数被废弃了。

  • 处理程序()

  • 处理程序(Handler.Callback)

    谷歌解释了下面的原因。

    在构建处理程序时隐含地选择一个Looper 处理程序构建过程中隐式地选择Looper,可能会导致操作被悄悄丢失的错误 丢失(如果处理程序不期望有新的任务并退出)、崩溃 (崩溃(如果有时在一个没有Looper的线程上创建处理程序 活动的线程上创建处理程序),或者竞赛条件,即处理程序所关联的线程 与之相关的线程不是作者所预期的。相反,使用一个执行器或 明确指定Looper,使用Looper#getMainLooper,{link android.view.View#getHandler},或类似的方法。如果隐含的线程 本地行为是为了兼容,请使用new Handler(Looper.myLooper(), callback)来让读者明白。

    Solution 1: 使用一个 Executor

    1. 在主线程中执行代码。

    // 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.在一个后台线程中执行代码

    // 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:记住在使用后要关闭执行器。

    backgroundExecutor.shutdown(); // or backgroundExecutor.shutdownNow();
    

    3.在一个后台线程中执行代码 and update UI on the main thread.

    // 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:通过使用以下构造函数之一明确指定一个Looper。

  • 处理程序(Looper)

  • Handler(Looper, Handler.Callback)

    1.在主线程中执行代码

    1.1.带循环器的处理程序

    Handler mainHandler = new Handler(Looper.getMainLooper());
    

    Kotlin

    val mainHandler = Handler(Looper.getMainLooper())
    

    1.2带循环器的处理程序 and a Handler.Callback

    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.
    

    2.在一个后台线程中执行代码

    2.1.带循环器的处理程序

    // 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.带循环器的处理程序 and a Handler.Callback

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

    Note:记得使用后要松开线。

    handlerThread.quit(); // or handlerThread.quitSafely();
    

    3.在一个后台线程中执行代码 and update UI on the main thread.

    // 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 {
        
  • 真棒的东西!欢呼声
    KK_07k11A0585
    天才!!!最佳答案
    Nicolas Jafelle
    Nicolas Jafelle
    发布于 2022-06-07
    0 人赞同

    如果你想避免Kotlin中的空检查( ? !! ),你可以使用 Looper.getMainLooper() ,如果你的 Handler 正在处理一些与UI相关的事情,像这样。

    Handler(Looper.getMainLooper()).postDelayed({
       Toast.makeText(this@MainActivity, "LOOPER", Toast.LENGTH_SHORT).show()
    }, 3000)
    

    注意:如果你使用片段,请使用requireContext()而不是this@MainActivity

    Gabe Sechan
    Gabe Sechan
    发布于 2022-06-07
    0 人赞同

    废弃的函数是处理程序的构造函数。 使用 Handler(Looper.myLooper()) .postDelayed(runnable, delay) 代替

    这在Kotlin中不起作用,因为 Looper.myLooper() 会返回一个 Looper? (可能为空值)。
    @EllenSpertus 然后添加一个空值检查,或者使用Looper.myLooper()!!,如果它是空的,就会抛出一个NPE。 如果你在一个有循环器的线程上,它将返回非空值。 如果不是,它将返回null,在任何语言中都应该抛出一个异常。
    Francesc
    Francesc
    发布于 2022-06-07
    0 人赞同

    Consider using coroutines

    scope.launch {
        delay(3000L)
        // do stuff
        
    Inside Activity or Fragment : lifecycleScope.launch { delay(3000L) }
    Shaon
    Shaon
    发布于 2022-06-07
    0 人赞同

    使用生命周期范围,这就更容易了。在活动或片段中。

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

    或使用处理程序

            Handler(Looper.myLooper()!!)
        
    如何避免使用!!操作者?
    它可能是空的,所以你必须写!以确保它不是空的。
    Bawa
    这样做!!可能会引起异常,因为循环器可能是空的,而处理程序需要一个不可空的值。
    Nguyen Thanh Son
    Nguyen Thanh Son
    发布于 2022-06-07
    0 人赞同

    我有 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({
            Thread.sleep(3000)
        } catch (e : Exception) {
            throw e
         // code
    }).start()
        
  • Dinith Rukshan Kumara
    Dinith Rukshan Kumara
    发布于 2022-06-07
    0 人赞同

    Handler() and Handler(Handler.Callback callback) constructors are deprecated. Because those can leads to bugs & crashes. Use Executor or Looper explicitly.

    对于Java

    Handler handler = new Handler(Looper.getMainLooper());
    handler.postDelayed(new Runnable() {
      @Override
      public void run() {
        //do your work here
    }, 1000);
        
    Muhammad Nasir Aziz
    Muhammad Nasir Aziz
    发布于 2022-06-07
    0 人赞同

    use this

    Looper.myLooper()?.let {
        Handler(it).postDelayed({
            //Your Code
        },2500)
        
    ajithvgiri
    ajithvgiri
    发布于 2022-06-07
    0 人赞同

    使用Executor而不是handler来获取更多信息 Executor .
    为了实现后延迟,使用 ScheduledExecutorService

    ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
    Runnable runnable = () -> {
        public void run() {
            // Do something
    worker.schedule(runnable, 2000, TimeUnit.MILLISECONDS);
        
    iFarbod
    这并不是一个糟糕的答案,事实上,即使是 google recommends this .
    Jeremiah Polo
    Jeremiah Polo
    发布于 2022-06-07
    0 人赞同

    在处理程序构造器中提供一个循环器

    Handler(Looper.getMainLooper())
        
    user2168735
    user2168735
    发布于 2022-06-07
    0 人赞同
    import android.os.Looper
    import android.os.Handler
    inline fun delay(delay: Long, crossinline completion: () -> Unit) {
        Handler(Looper.getMainLooper()).postDelayed({
            completion()
        }, delay)
    
    delay(1000) {
        view.refreshButton.visibility = View.GONE
        
    0 人赞同

    如果你在处理程序和Runnable中使用Variable,那么就像这样使用。

    private Handler handler;
    private Runnable runnable;
    handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(runnable = () -> {
            // Do delayed stuff here
             handler.postDelayed(runnable, 1000);
        }, delay);
    

    你还需要删除onDestroy()中的回调。

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (handler != null) {
            handler.removeCallbacks(runnable);
        
    Abdul Mateen
    Abdul Mateen
    发布于 2022-06-07
    0 人赞同

    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()
        
    Cagdas
    我认为GlobalScope与处理程序之间没有区别。GlobalScope不知道生命周期(除了应用程序的过程)。在我看来,根据GlobalScope,生命周期范围或自定义范围是更方便的方式。
    nmahnic
    nmahnic
    发布于 2022-06-07
    0 人赞同

    在Kotlin中使用这种结构是一个好主意

    companion object Run {
       fun after(delay: Long, process: () -> Unit) {
          Handler(Looper.getMainLooper()).postDelayed({
              process()
          }, delay)
    

    后来被称为

    Run.after(SPLASH_TIME_OUT) {
       val action = SplashFragmentDirections.actionSplashFragmentToLogin()
       v.findNavController().navigate(action)
        
    jamescodingnow
    jamescodingnow
    发布于 2022-06-07
    0 人赞同

    Java答案

    我写了一个方法,可以轻松使用。你可以在你的项目中直接使用这个方法。 延迟时间Millis 可以是2000,这意味着这段代码将运行 之后 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);
        
    KNOX.C
    KNOX.C
    发布于 2022-06-07
    0 人赞同

    根据该文件( https://developer.android.com/reference/android/os/Handler#Handler() ):

    在处理程序构建过程中隐含地选择一个Looper可能会导致一些错误,如操作被悄悄地丢失(如果处理程序不期望新的任务并退出),崩溃(如果处理程序有时在没有Looper活动的线程上创建),或竞赛条件,即处理程序所关联的线程不是作者预期的。相反,使用Executor或明确指定Looper,使用Looper#getMainLooper,{link android.view.View#getHandler},或类似的方法。如果为了兼容需要隐含的线程本地行为,使用new Handler(Looper.myLooper())来向读者说明。

    我们应该停止使用没有Looper的构造函数,而是指定一个Looper。

    0 人赞同

    我通常使用这个

    Code:

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

    Screenshot:

    matrixmike
    matrixmike
    发布于 2022-06-07
    0 人赞同

    处理程序()等代码是由Android Studio 4.0.1生成的,比如说,当一个全屏活动从头开始创建时。我知道我们被鼓励使用Kotlin,我也是这样做的,但我不时地使用样本项目来获得一个想法。 奇怪的是,当AS实际生成代码时,我们却受到AS的责备。仔细检查错误并修复它们可能是一个有用的学术活动,但也许AS可以为我们这些爱好者生成新的干净的代码......

    stonito
    stonito
    发布于 2022-06-07
    0 人赞同

    对于Xamarin Android来说,代替

    Handler handler;
    handler = new Handler();