【问题标题】:What do I use now that Handler() is deprecated?现在 Handler() 已弃用,我该使用什么?
【发布时间】:2020-07-16 08:04:05
【问题描述】:

如何修复此代码中的弃用警告?或者,还有其他选择吗?

Handler().postDelayed({
    context?.let {
        //code
    }
}, 3000)

【问题讨论】:

    标签: java android kotlin android-handler


    【解决方案1】:

    我有 3 个解决方案

    1. 明确指定 Looper:
      Handler(Looper.getMainLooper()).postDelay({
          // code
      })
      
    2. 指定隐式线程本地行为:
      Handler(Looper.myLooper()!!).postDelay({
          // code
      })
      
    3. 使用Thread:
      Thread({
          try{
              Thread.sleep(3000)
          } catch (e : Exception) {
              throw e
          }
           // code
      }).start()
      `
      

    【讨论】:

      【解决方案2】:

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

      在 Handler 构造过程中隐式选择 Looper 可能会导致操作丢失(如果 Handler 不期待新任务并退出)、崩溃(如果有时在没有 Looper 活动的线程上创建处理程序)或竞争条件,其中处理程序关联的线程不是作者预期的。相反,使用 Executor 或显式指定 Looper,使用 Looper#getMainLooper、{link android.view.View#getHandler} 或类似方法。如果为了兼容性需要隐式线程本地行为,请使用 new Handler(Looper.myLooper()) 让读者清楚。

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

      【讨论】:

        【解决方案3】:

        Handler()Handler(Handler.Callback callback) 构造函数已弃用。因为这些会导致错误和崩溃。明确使用 Executor 或 Looper。

        对于 Java

        Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
          @Override
          public void run() {
            //do your work here
           }
        }, 1000);
        

        【讨论】:

          【解决方案4】:

          Java 答案

          我写了一个易于使用的方法。您可以直接在项目中使用此方法。 delayTimeMillis 可以是 2000,表示这段代码将在 2 秒后运行。

          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);
          }
          

          【讨论】:

            【解决方案5】:

            使用生命周期范围更容易。内部活动或片段。

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

            或使用处理程序

                    Handler(Looper.myLooper()!!)
            

            【讨论】:

            • 如何避免!!运算符?
            • 它可以为空,所以你必须写!!确保它不为空
            【解决方案6】:

            在 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)
            }
            

            【讨论】:

              【解决方案7】:

              协程 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()
              }
              

              【讨论】:

              • 我认为 GlobalScope 与 Handler 之间没有区别。 GlobalScope 不知道生命周期(应用程序进程除外)。在我看来,根据 GlobalScope,生命周期范围或自定义范围更方便。
              【解决方案8】:

              如果你使用 Handler 和 Runnable 的变量,那么像这样使用它。

              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);
                  }
              }
              

              【讨论】:

                【解决方案9】:

                仅不推荐使用无参数构造函数,现在最好通过Looper.getMainLooper() 方法在构造函数中指定Looper

                为 Java 使用它

                new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        // Your Code
                    }
                }, 3000);
                

                将它用于 Kotlin

                Handler(Looper.getMainLooper()).postDelayed({
                    // Your Code
                }, 3000)
                

                【讨论】:

                  【解决方案10】:

                  我经常用这个

                  代码:

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

                  截图:

                  【讨论】:

                    【解决方案11】:

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

                    Google 解释了以下原因。

                    隐式选择 Looper 处理程序构造可能导致操作静默的错误 丢失(如果处理程序不期待新任务并退出),崩溃 (如果有时在没有 Looper 的线程上创建处理程序 活动)或竞争条件,其中与处理程序关联的线程 与作者的预期不同。相反,使用 Executor 或 明确指定 Looper,使用 Looper#getMainLooper, {link android.view.View#getHandler},或类似的。如果隐式线程 本地行为是兼容性所必需的,请使用新的 Handler(Looper.myLooper(), callback) 让读者一目了然。

                    解决方案 1: 使用 Executor

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

                    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.
                        }
                    });
                    

                    科特林

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

                    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);
                    

                    科特林

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

                    注意:使用后记得关闭执行器。

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

                    3.在后台线程中执行代码并在主线程中更新UI。

                    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.
                                }
                            });
                        }
                    });
                    

                    科特林

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

                    解决方案 2: 使用以下构造函数之一显式指定 Looper。

                    1.在主线程中执行代码

                    1.1. 带有 Looper 的处理程序

                    Java

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

                    科特林

                    val mainHandler = Handler(Looper.getMainLooper())
                    

                    1.2 带有 Looper 和 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;
                        }
                    });
                    

                    科特林

                    val mainHandler = Handler(Looper.getMainLooper(), Handler.Callback {
                        // Your code logic goes here.
                        true
                    })
                    

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

                    2.1. 带有 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()); 
                    

                    科特林

                    // 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. 带有 Looper 和 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;
                        }
                    });
                    

                    科特林

                    // 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
                    })
                    

                    注意:使用后记得释放线程。

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

                    3.在后台线程中执行代码并在主线程中更新UI。

                    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;
                        }
                    });
                    

                    科特林

                    // 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
                    })
                    

                    【讨论】:

                    • 好东西!干杯
                    【解决方案12】:

                    如果您想避免 Kotlin 中的空值检查(?!!),如果您的 Handler 正在处理一些与 UI 相关的事情,则可以使用 Looper.getMainLooper(),如下所示:

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

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

                    【讨论】:

                      【解决方案13】:

                      在Handler构造函数中提供一个looper

                      Handler(Looper.getMainLooper())
                      

                      【讨论】:

                        【解决方案14】:

                        使用 Executor 而不是处理程序获取更多信息Executor
                        要实现后期延迟,请使用ScheduledExecutorService

                        ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
                        Runnable runnable = () -> {
                            public void run() {
                                // Do something
                            }
                        };
                        worker.schedule(runnable, 2000, TimeUnit.MILLISECONDS);
                        

                        【讨论】:

                        【解决方案15】:

                        例如,当从头开始创建全屏活动时,Android Studio 4.0.1 会生成 handler() 等代码。我知道我们被鼓励使用 Kotlin,我确实这样做了,但我不时使用示例项目来获得一个想法。 当 AS 实际生成代码时,我们被 AS 责备,这似乎很奇怪。解决错误并修复它们可能是一项有用的学术活动,但也许 AS 可以为我们这些爱好者生成新的干净代码......

                        【讨论】:

                          【解决方案16】:

                          使用这个

                          Looper.myLooper()?.let {
                              Handler(it).postDelayed({
                                  //Your Code
                              },2500)
                          }
                          

                          【讨论】:

                            【解决方案17】:

                            不推荐使用的函数是 Handler 的构造函数。请改用Handler(Looper.myLooper()) .postDelayed(runnable, delay)

                            【讨论】:

                            • 这在 Kotlin 中不起作用,因为 Looper.myLooper() 返回一个 Looper?(可能为 null 值)。
                            • @EllenSpertus 然后添加一个空检查,或者使用 Looper.myLooper()!如果它为空,它将抛出一个 NPE。如果你在一个带有 looper 的线程上,它将返回非空值。如果不是,它将返回 null 并且应该以任何语言抛出异常。
                            【解决方案18】:

                            考虑使用协程

                            scope.launch {
                                delay(3000L)
                                // do stuff
                            }
                            

                            【讨论】:

                            • ActivityFragment 内部:lifecycleScope.launch { delay(3000L) }
                            猜你喜欢
                            • 2021-07-14
                            • 1970-01-01
                            • 2016-10-14
                            • 2013-03-07
                            • 2021-03-10
                            • 1970-01-01
                            • 1970-01-01
                            • 2015-02-17
                            相关资源
                            最近更新 更多