现在 Handler() 已弃用,我该用什么?

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

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

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

使用 Executor 而不是 handler 获取更多信息 Executor
要实现 post 延迟使用 ScheduledExecutorService:

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

考虑使用协程

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

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

根据文档 (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.

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

如果你想避免 Kotlin 中的空值检查(?!!)你可以使用 Looper.getMainLooper() 如果你的 Handler 正在使用一些 UI相关的东西,像这样:

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

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

使用这个

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

handler() 等代码由 Android Studio 4.0.1 在全屏 Activity 等从头创建时生成。我知道我们被鼓励使用 Kotlin,我也这样做了,但有时我会使用示例项目来实现一个想法。 当AS真正生成代码的时候,我们却被AS责骂,这似乎很奇怪。研究错误并修复它们可能是一个有用的学术 activity 但也许 AS 可以为我们的爱好者生成新的干净代码...

仅弃用了无参数构造函数,现在建议您通过 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)

在处理程序构造函数中提供循环程序

Handler(Looper.getMainLooper())

使用生命周期范围更容易。在 activity 或片段内。

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

或使用处理程序

        Handler(Looper.myLooper()!!)

Java 回答

我写了一个方法,方便使用。您可以直接在您的项目中使用此方法。 delayTimeMillis可以是2000,就是说这段代码会运行after2秒。

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

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

Google 下面解释原因。

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.

解决方案 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.
    }
});

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

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)

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

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

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

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

1.在主线程中执行代码

1.1. 带 Looper 的处理程序

Java

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

Kotlin

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

Kotlin

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

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

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

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

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

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

我经常用这个

代码:

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

截图:

如果你为 Handler 和 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);
    }
}

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

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

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

我有 3 个解决方案:

  1. 明确指定 Looper:
    Handler(Looper.getMainLooper()).postDelayed({
        // code
    }, duration)
    
  2. 指定隐式线程本地行为:
    Handler(Looper.myLooper()!!).postDelayed({
        // code
    }, duration)
    
  3. 使用Thread
    Thread({
        try{
            Thread.sleep(3000)
        } catch (e : Exception) {
            throw e
        }
         // code
    }).start()
    
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
}