DEV Community

kouwei qing
kouwei qing

Posted on

Functional Anomaly of Event Cancellation Caused by Dual Navigation Lifecycles

HarmonyOS Next IM Combat: Functional Anomaly of Event Cancellation Caused by Dual Navigation Lifecycles

Background Introduction

Users of the IM application's chat page reported being unable to view large images by clicking on them. Code review showed that the large image click used the ohos.events.emitter event mechanism. Further investigation revealed that events were emitted but not consumed. Logs indicated successful event registration, but no event reception.

Problem Diagnosis

Further analysis showed the issue consistently occurred when cold-starting the app by clicking a notification, while hot-starting via a push notification worked normally. Both company apps integrated HarmonyOS's PushKit to receive notifications when backgrounded or closed, but only one exhibited the problem.

Log analysis revealed that cold-starting the app from a notification and entering the chat page triggered one aboutToAppear and one proactive aboutToDisappear in the chat page. Further inspection showed the chat page's lifecycle was executed twice: Chat Page 1 aboutToAppear → Chat Page 2 aboutToAppear → Chat Page 2 aboutToDisappear.

Initially suspected to relate to PushKit, the hypothesis was dismissed when the other app functioned normally. Clicking a notification triggers navigation to the chat page via onNewWant. Expert consultation suggested the issue might stem from multiple Navigation instances in the app.

Code review revealed that after a cold start, the app did not immediately navigate to the chat page in onNewWant but waited for the home page to load, then navigated to the chat page in the home page's aboutToAppear. The app loads a splash screen in onWindowStageCreate, navigates from the splash screen's aboutToAppear to the home page, and then from the home page's aboutToAppear to the chat page. The splash screen and home page are two Navigation instances sharing a NavPathStack.

Understanding Navigation lifecycles: As a routing container, Navigation lifecycles are hosted on NavDestination components, exposed as component events. Lifecycles fall into three categories: custom component lifecycles, universal component lifecycles, and proprietary lifecycles. aboutToAppear and aboutToDisappear are custom component lifecycles (for the custom component wrapping NavDestination), while onAppear and onDisappear are universal component lifecycles. The remaining lifecycles are unique to NavDestination.

Lifecycle timeline:

text

  • aboutToAppear: Executed after creating a custom component and before its build() function (before NavDestination creation). Allows modifying state variables, which take effect in the subsequent build() execution.
  • onWillAppear: Executed after NavDestination creation and before mounting to the component tree. State changes here take effect in the current frame.
  • onAppear: Universal lifecycle event triggered when NavDestination mounts to the component tree.
  • onWillShow: Executed before NavDestination is layout-displayed (not triggered when the app switches to the foreground).
  • onShown: Executed after NavDestination is layout-displayed, indicating layout completion.
  • onActive: Triggered when NavDestination is active (at the stack top and operable, with no special components obscuring it).
  • onWillHide: Executed before NavDestination is hidden (not triggered when the app switches to the background).
  • onInactive: Triggered when NavDestination is inactive (not at the stack top or obscured by special components when at the stack top).
  • onHidden: Executed after NavDestination is hidden (when a new page is pushed, the top page is popped, or the app switches to the background).
  • onWillDisappear: Executed before NavDestination is destroyed. If there is a transition animation, it triggers before the animation (when the top page is popped).
  • onDisappear: Universal lifecycle event triggered when NavDestination is unmounted and destroyed from the component tree.
  • aboutToDisappear: Executed before a custom component is destructed; state variable modifications are prohibited.

The lifecycle when navigating from Page A to Page B is: A aboutToAppear → B aboutToAppear → A aboutToDisappear.

The root cause was identified: When navigating to the chat page in the home page's aboutToAppear, the splash screen's aboutToDisappear had not completed, leaving both Navigation instances active. This caused the chat page to execute aboutToAppear twice. After the splash screen's aboutToDisappear, the second chat page instance was automatically aboutToDisappeared, canceling event subscriptions.

Solution

After identifying the problem, the fix involved adding a 20ms delay to the chat page navigation, resolving the issue. A more elegant solution is to navigate to the chat page after the splash screen's aboutDisappear or modify the splash screen to a non-Navigation structure.

Summary

Step-by-step troubleshooting revealed the root cause: Cold-starting the app with two Navigation components (splash screen and home page) sharing a NavPathStack caused the chat page to be repeatedly created and destroyed when navigating from the home page's aboutToAppear before the splash screen's aboutToDisappear completed. This invalidated event subscriptions (as the second page instance did not register event consumption logic). Solutions include delaying navigation, adjusting navigation timing until the splash screen is destroyed, or restructuring the splash screen as a non-Navigation to eliminate multi-Navigation coexistence. This case highlights the complexity of Navigation lifecycle management in HarmonyOS, emphasizing the need to strictly follow component mounting/unmounting order in multi-page navigation to avoid lifecycle conflicts.

Reference: Component Navigation (Navigation) (Recommended): https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-navigation-navigation#%E9%A1%B5%E9%9D%A2%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F

Top comments (0)