DEV Community

HarmonyOS
HarmonyOS

Posted on

How to solve the problem that the corresponding UI is not refreshed when the value of Provide modifier is changed

Read the original article:How to solve the problem that the corresponding UI is not refreshed when the value of Provide modifier is changed

Problem Description

A state variable is declared using the @Provide decorator, and data is modified using methods provided by other classes. However, this does not trigger a UI refresh, and the data on the page remains unchanged. The following is a sample code for the problem:

Index.ets page

// Index.ets
import currentPlayInfo, { PlayInfo } from './PlayInfo'
import player from './AVPlayer'

@Entry
@Component
struct Index {
  @Provide('pageStack') pageStack: NavPathStack = new NavPathStack()
  @Provide('playInfo') playInfo: PlayInfo = currentPlayInfo

  build() {
    Navigation(this.pageStack) {
      Column() {
        if (this.playInfo.isPlaying) {
          Text('Playing: ' + this.playInfo.title)
            .fontSize(30)
            .fontWeight(FontWeight.Bold)
            .alignRules({
              center: { anchor: '__container__', align: VerticalAlign.Center },
              middle: { anchor: '__container__', align: HorizontalAlign.Center }
            })
        } else {
          Text('Not playing')
            .fontSize(30)
        }
        Text('Change PlayInfo')
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
          .alignRules({
            center: { anchor: '__container__', align: VerticalAlign.Center },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
          .onClick(() => {
            player.play();
          })
      }
      .height('100%')
      .width('100%')
    }
    .hideTitleBar(true)
  }
}
Enter fullscreen mode Exit fullscreen mode

Encapsulate the PlayInfo class and export the global instance object to the Index.ets page

// PlayInfo.ets
export class PlayInfo {
  isPlaying: boolean = false
  title: string = ''
}

let currentPlayInfo = new PlayInfo();

export default currentPlayInfo as PlayInfo;
Enter fullscreen mode Exit fullscreen mode

Encapsulates the AVPlayer method class to modify the playback data.

// AVPlayer.ets
import currentPlayInfo from './PlayInfo'
class AVPlayer {
  play() {
    currentPlayInfo.isPlaying = !currentPlayInfo.isPlaying;
    currentPlayInfo.title = 'Track ' + Math.round(Math.random() * 100);
  }
}
let player = new AVPlayer();
export default player as AVPlayer;
Enter fullscreen mode Exit fullscreen mode

When you click the "Change PlayInfo" text, you want the text "Not playing" to be updated to "Playing song XX". The problem phenomenon is shown in the figure below:

image.png

Background Knowledge

  • State Management Overview : In a declarative UI programming framework, the UI is the result of the program state. The user builds a UI model in which the runtime state of the application is a parameter. When the parameter changes, the UI, as the return result, will also change accordingly. The re-rendering of the UI caused by these runtime state changes is collectively referred to as the state management mechanism in ArkUI. Custom components have variables, and variables must be decorated with decorators to become state variables. Changes in state variables will cause the UI rendering to refresh. If state variables are not used, the UI can only be rendered at initialization and will not be refreshed subsequently. The following figure shows the relationship between State and View (UI). img​​
  • View (UI): UI rendering refers to mapping the UI description in the build method and the UI description in the @Builder decorated method to the interface.
  • State: The data that drives UI updates. Users change state data by triggering component events. Changes to state data cause the UI to re-render.
  • State variables: Variables decorated with state decorators. Changes to state variable values will cause UI rendering updates. Example: @State num: number = 1, where @State is a state decorator and num is a state variable.
  • Regular variables: variables that are not decorated by state decorators, usually used for auxiliary calculations. Its changes will never cause the UI to refresh

  • @Provide/@Comsume decorator : This decorator is a state management decorator that can realize the sharing and two-way synchronization of component data with descendant components, and can realize synchronous refresh of UI when modification occurs.

Troubleshooting Process

  1. In the ArkUI programming framework, page refresh requires refreshing the UI interface by modifying the state variables decorated by the state decorator.
  2. The @Provide decorator proxies the decorated state variable to a proxy object. In the problematic code example, the proxy object is playInfo, not currentPlayInfo. Therefore, although the play() method in the AVPlayer class modifies the currentPlayInfo object, the currentPlayInfo object is a regular variable and therefore cannot refresh the UI.

Analysis Conclusion

play() modifies the normal variable currentPlayInfo, not the state variable playInfo, so it will not trigger a UI refresh. play() needs to modify the state variable playInfo to refresh the UI.

Solution

Change the normal variable currentPlayInfo that is modified by the play() method in the AVPlayer class to the state variable playInfo. Since the state variable playInfo is not a global instance object and cannot be modified by importing it, override the play() method and pass in the state variable playInfo when calling it to modify it. Modify it as follows:

1.Rewrite the play() method to a function that requires parameters.

   // AVPlayer.ets
   class AVPlayer {
     playNew(playInfo: PlayInfo) {
       playInfo.isPlaying = !playInfo.isPlaying;
       playInfo.title = 'Track ' + Math.round(Math.random() * 100);
     }
   }
Enter fullscreen mode Exit fullscreen mode

2.Pass the state variable playInfo to implement click modification and refresh the UI interface.

   / Index.ets
   Text('Change PlayInfo')
     .fontSize(30)
     .fontWeight(FontWeight.Bold)
     .alignRules({
       center: { anchor: '__container__', align: VerticalAlign.Center },
       middle: { anchor: '__container__', align: HorizontalAlign.Center }
     })
     .onClick(() => {
       // The state variable needs to be modified to drive UI updates
       player.playNew(this.playInfo as PlayInfo);
     })
Enter fullscreen mode Exit fullscreen mode
  • ArkUI is a declarative UI programming framework based on the MVVM pattern. It drives UI updates through changes in state variables. Therefore, when the UI needs to be updated, the corresponding state variables need to be modified.
  • Variables or objects that are not decorated by decorators are mainly used for type declaration, initialization, calculation, etc. Modifying such ordinary variables cannot directly cause the refresh of UI data.

Verification Result

Code running effect diagram :

image.png

Limitations or Considerations

  • This example supports API Version 19 Release and above.
  • This example supports HarmonyOS 5.1.1 Release SDK and above.
  • This example requires DevEco Studio 5.1.1 Release and above to compile and run

Written by Muhammet Cagri Yilmaz

Top comments (0)