android ios
Sometimes we want our App to perform some task when it is put to background (e.g. to save some data) or they are brought back to foreground (e.g. to sync some data).
小号 ometimes我们希望当它被放到背景我们的应用程序来执行一些任务(例如保存一些数据),或者他们带回前景(如同步一些数据)。
Here I share how they are done on both iOS and Android, to know their similarity and differences.
在这里,我分享了它们在iOS和Android上的完成方式,以了解它们的异同。
如何检测onBackground / onForeground (How to detect onBackground/onForeground)
在iOS中 (In iOS)
iOS natively provides ability to track onBackground or onForeground easily, in AppDelegate
(before iOS 13) and in SceneDelegate
(default in iOS 13).
iOS本身提供了在AppDelegate
(iOS 13之前)和SceneDelegate
(iOS 13中的默认设置)中轻松跟踪onBackground或onForeground的功能。
// App Delegate (pre iOS 13.0, where one uses App Delegate)func applicationWillEnterForeground(_ application: UIApplication)func applicationDidEnterBackground(_ application: UIApplication)// Scene Delegate (iOS 13.0 onward, when one uses Scene/s)func sceneWillEnterForeground(_ scene: UIScene)func sceneDidEnterBackground(_ scene: UIScene)
If one like to support both iOS 13 and older OS, use
AppDelegate
approach如果想同时支持iOS 13和旧版操作系统,请使用
AppDelegate
方法
在Android中 (In Android)
Prior to Architecture Component introduced (before 2017), the approach used is ActivityLifecycleCallback
as mentioned this Stackoverflow. It’s quite troublesome to use as one need to detect the active activities count, as on top of that, also need to ensure it is not due to onConfigurationChange. One word, complicating.
在引入Architecture Component之前(2017年之前),使用的方法是ActivityLifecycleCallback
如本Stackoverflow所述 。 使用它非常麻烦,因为它需要检测活动活动计数,此外,还需要确保它不是由于onConfigurationChange引起的 。 一个字,很复杂。
In 2017, with Architecture Component in place, Google introduced ProcessLivecycleOwner, where one could be informed of the Application came on foreground or get into background. Sample code could be found in this stackoverflow
在2017年,有了架构组件,Google引入了ProcessLivecycleOwner ,可以在其中通知应用程序进入前台或进入后台。 在此stackoverflow中可以找到示例代码
In short, I need to create a LifecycleObserver
, when map it to ON_START
and ON_STOP
to be notified of the status.
简而言之,当将其映射到ON_START
和ON_STOP
时,我需要创建一个LifecycleObserver
,以通知其状态。
class MainLifecycleListener: LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onMoveToForeground() { ...} @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onMoveToBackground() { ... }}
In the MainApplication
, just need to instantiate the MainLifecycleListener
and register it to ProcessLifecycleOwner
.
在MainApplication
,只需实例化MainLifecycleListener
并将其注册到ProcessLifecycleOwner
。
class MainApplication: Application() { private val lifecycleListener: MainLifecycleListener by lazy {MainLifecycleListener()}override fun onCreate() { super.onCreate() setupLifecycleListener() } private fun setupLifecycleListener() { ProcessLifecycleOwner.get() .lifecycle.addObserver(lifecycleListener) }}
他们什么时候被叫 (When will they be called)
在iOS中 (In iOS)
As shown in diagram, the applicationWillEnterForeground
is not called when the App first launch. It is only called subsequently after the app has been background and re-foreground.
如图所示,App首次启动时未调用applicationWillEnterForeground
。 仅在应用程序已后台运行并重新运行后才调用。
在Android中 (In Android)
As shown in diagram above, differ from iOS, the ON_START
is triggered both during app launch as well as normal bring to foreground.
如上图所示,与iOS不同, ON_START
在应用启动过程中以及正常进入前台时都会触发。
This is one main different between the two platforms one need to be aware of.
这是需要注意的两个平台之间的主要区别。
是否保留了onBackground任务? (Is the onBackground task preserved?)
Here, we investigate the onBackground task, if they are executed to completion, or would be suspended.
在这里,我们调查onBackground任务(如果它们已执行完毕或将被暂停)。
We’re not checking onForeground, as foreground app will have the priority of task execution.
我们不检查onForeground,因为前台应用程序将优先执行任务。
在iOS中 (In iOS)
When executed on main thread synchronously as below, all the background task will be completed.
当在主线程上以如下方式同步执行时,所有后台任务将完成。
func applicationDidEnterBackground(_ application: UIApplication) { print("Track: Background \(Thread.current)") print("Track: Enter Background DispatchQueue \(Thread.current)") for index in 1...10 { sleep(1) print("Track: After Background DispatchQueue \(index)") }}
When executed on main thread asynchronous as below, all the background task will be completed.
在如下异步地在主线程上执行时, 将完成所有后台任务。
func applicationDidEnterBackground(_ application: UIApplication) { print("Track: Background \(Thread.current)") DispatchQueue.main.async { print("Track: Enter Background DispatchQueue \(Thread.current)") for index in 1...10 { sleep(1) print("Track: After Background DispatchQueue \(index)") } }}
However if executed on main thread asynchronous with some delay as below, all the background task will NOT be completed. It continue as the app on foreground again.
但是,如果在异步异步执行的主线程上执行以下延迟,则所有后台任务将无法完成。 它继续作为应用程序再次出现在前台。
func applicationDidEnterBackground(_ application: UIApplication) { print("Track: Background \(Thread.current)") DispatchQueue.main.asyncAfter(deadline: .now() + 1) { print("Track: Enter Background DispatchQueue \(Thread.current)") for index in 1...10 { sleep(1) print("Track: After Background DispatchQueue \(index)") } }}
If executed on another thread asynchronous without any delay, all the background task will NOT be completed. It continue as the app on foreground again.
如果在异步的另一个线程上执行而没有任何延迟,则所有后台任务都不会完成。 它继续作为应用程序再次出现在前台。
func applicationDidEnterBackground(_ application: UIApplication) { print("Track: Background \(Thread.current)") DispatchQueue.global().async { print("Track: Enter Background DispatchQueue \(Thread.current)") for index in 1...10 { sleep(1) print("Track: After Background DispatchQueue \(index)") } }}
If executed on another thread asynchronous with some delay, all the background task will NOT be completed. It continue as the app on foreground again.
如果在另一个具有异步延迟的线程上执行,则所有后台任务将无法完成。 它继续作为应用程序再次出现在前台。
func applicationDidEnterBackground(_ application: UIApplication) { print("Track: Background \(Thread.current)") DispatchQueue.global().asyncAfter(deadline: .now() + 1) { print("Track: Enter Background DispatchQueue \(Thread.current)") for index in 1...10 { sleep(1) print("Track: After Background DispatchQueue \(index)") } }}
To ensure delayed or another thread task executed to completion, we’ll need to use UIApplication.shared.beginBackgroundTask(...)
as recommended by Apple.
为了确保延迟执行或其他线程任务执行完毕,我们需要按照Apple的建议使用UIApplication.shared.beginBackgroundTask(...)
。
func applicationDidEnterBackground(_ application: UIApplication) {var backgroundTaskID: UIBackgroundTaskIdentifier? backgroundTaskID = UIApplication.shared.beginBackgroundTask (withName: "Finish Background Tasks") { backgroundTaskID = self.endBackgroundTask( backgroundTaskID: backgroundTaskID) } guard backgroundTaskID?.rawValue != UIBackgroundTaskIdentifier.invalid.rawValue else { return } print("Track: Background \(Thread.current)") DispatchQueue.global().asyncAfter(deadline: .now() + 1) { print("Track: Enter Background DispatchQueue \(Thread.current)")for index in 1...10 { sleep(1) print("Track: After Background DispatchQueue \(index)") } backgroundTaskID = self.endBackgroundTask( backgroundTaskID: backgroundTaskID) }}func endBackgroundTask(backgroundTaskID: UIBackgroundTaskIdentifier?) -> UIBackgroundTaskIdentifier { if let backgroundTaskID = backgroundTaskID, backgroundTaskID != UIBackgroundTaskIdentifier.invalid { UIApplication.shared.endBackgroundTask(backgroundTaskID) }return UIBackgroundTaskIdentifier.invalid}
在Android中 (In Android)
For Android, the experiment result as below.
对于Android,实验结果如下。
When executed on main thread synchronously as below, all the background task will be completed.
当在主线程上以如下方式同步执行时,所有后台任务将完成。
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)fun onMoveToBackground() {println("Track: Background ${Thread.currentThread()}")println("Track: Enter Background handler ${Thread.currentThread()}") for (index in 1..10) { Thread.sleep(ONE_SECOND)println("Elye: After Background handler $index") }}
When executed on main thread asynchronous as below, all the background task will be completed.
在如下异步地在主线程上执行时, 将完成所有后台任务。
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)fun onMoveToBackground() {println("Track: Background ${Thread.currentThread()}")Handler().post {println("Track: Enter Background handler ${Thread.currentThread()}") for (index in 1..10) { Thread.sleep(ONE_SECOND)println("Elye: After Background handler $index") }}}
However if executed on main thread asynchronous with some delay as below, all the background task will be completed.
但是,如果在异步异步执行的主线程上执行如下所示的某些延迟,则所有后台任务将完成。
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)fun onMoveToBackground() {println("Track: Background ${Thread.currentThread()}") Handler().postDelayed({println("Track: Enter Background handler ${Thread.currentThread()}") for (index in 1..10) { Thread.sleep(ONE_SECOND)println("Elye: After Background handler $index") } }, ONE_SECOND)}
However if executed on another thread asynchronous without delay as below, all the background task will be completed.
但是,如果在异步执行的另一个线程上执行如下所示,没有延迟,则所有后台任务将完成。
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)fun onMoveToBackground() {println("Track: Background ${Thread.currentThread()}") Handler(handlerThread.looper).post{println("Track: Enter Background handler ${Thread.currentThread()}") for (index in 1..10) { Thread.sleep(ONE_SECOND)println("Elye: After Background handler $index") } }}
However if executed on another thread asynchronous with some delay as below, all the background task will be completed.
但是,如果在异步执行的另一个线程上执行延迟如下,则所有后台任务都将完成。
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)fun onMoveToBackground() {println("Track: Background ${Thread.currentThread()}") Handler(handlerThread.looper).postDelayed({println("Track: Enter Background handler ${Thread.currentThread()}") for (index in 1..10) { Thread.sleep(ONE_SECOND)println("Elye: After Background handler $index") } }, ONE_SECOND)}
In short, the tasks will get completed regardless, as long as the App process is not killed by the system (beware, Android system tense to kill the app process more frequently than iOS)
简而言之,只要App进程没有被系统杀死,任务就可以完成(请注意,Android系统比iOS时态更频繁地杀死App进程)
Nevertheless, Android is introducing more and more restriction on its background task. Refer to the below update for more details.
尽管如此,Android对其后台任务引入了越来越多的限制。 有关更多详细信息,请参考以下更新。
摘要 (Summary)
翻译自: https://medium.com/swlh/ios-android-onbackground-onforeground-630a109de546
android ios