Requesting Frame Rates for Custom Content

When you use native APIs to develop an application based on the <XComponent>, you can request an independent frame rate for custom content in scenarios such as gaming and custom UI framework interconnection.

Available APIs

Name Description
OH_NativeXComponent_SetExpectedFrameRateRange (OH_NativeXComponent *component, OH_NativeXComponent_ExpectedRateRange *range) Sets the expected frame rate range.
OH_NativeXComponent_RegisterOnFrameCallback (OH_NativeXComponent *component, OH_NativeXComponent_OnFrameCallback *callback) Registers the display update callback and enables the callback for each frame.
OH_NativeXComponent_UnRegisterOnFrameCallback (OH_NativeXComponent *component) Deregisters the display update callback and disables the callback for each frame.

How to Develop

NOTE

This section draws a graphic through the native Drawing module and presents it using the native Window module. For details, see Using Drawing to Draw and Display Graphics.

  1. Define an ArkTS API file and name it XComponentContext.ts, which is used to connect to the native layer.

    export default interface XComponentContext {
    register(): void;
    unregister(): void;
    };
    
  2. Define a demo page, which contains two <XComponents>.

    @Entry
    @Component
    struct Index {
      private xComponentContext1: XComponentContext | undefined = undefined;
      private xComponentContext2: XComponentContext | undefined = undefined;
       Row() {
         XComponent({ id: 'xcomponentId_30', type: 'surface', libraryname: 'entry' })
           .onLoad((xComponentContext) => {
             this.xComponentContext1 = xComponentContext as XComponentContext;
           }).width('832px')
       }.height('40%')
    
       Row() {
         XComponent({ id: 'xcomponentId_120', type: 'surface', libraryname: 'entry' })
           .onLoad((xComponentContext) => {
             this.xComponentContext2 = xComponentContext as XComponentContext;
           }).width('832px')// Multiples of 64
       }.height('40%')
    }
    
  3. Configure the frame rate and register the callback function at the native layer.

    static void TestCallback(OH_NativeXComponent *component, uint64_t timestamp, uint64_t targetTimestamp) // Define the callback function for each frame.
    {
        // ...
        // Obtain the surface size of the XComponent.
        int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, nativeWindow, &width, &height);
        if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
            render->Prepare();
            render->Create();
            if (id == "xcomponentId_30") {
                // When the frame rate is 30 Hz, the frame moves by 16 pixels at a time.
                render->ConstructPath(16, 16, render->defaultOffsetY);
            }
            if (id == "xcomponentId_120") {
                // When the frame rate is 120 Hz, the frame moves by 4 pixels at a time.
                render->ConstructPath(4, 4, render->defaultOffsetY);
            }
      	 // ...
        }
    }
    

    NOTE

    • The callback function runs in the UI main thread. To avoid adverse impact on the performance, time-consuming operations related to the UI thread should not run in the callback function.
    • After the instance calls NapiRegister, it must call NapiUnregister when it no longer needs to control the frame rate, so as to avoid memory leakage.
    void SampleXComponent::RegisterOnFrameCallback(OH_NativeXComponent *nativeXComponent) 
    {
        OH_NativeXComponent_RegisterOnFrameCallback(nativeXComponent, TestCallback); // Register the callback function and enable callback for each frame.
    }
    
    napi_value SampleXComponent::NapiRegister(napi_env env, napi_callback_info info)
    {
        // ...
        render->RegisterOnFrameCallback(nativeXComponent); // Register the callback function and enable callback for each frame at the TS layer.
        // ...
    }
    
    napi_value SampleXComponent::NapiUnregister(napi_env env, napi_callback_info info)
    {
        // ...
        The OH_NativeXComponent_UnregisterOnFrameCallback(nativeXComponent); // Deregister the callback function for each frame at the TS layer.
        // ...
    }
    
  4. Register and deregister the callback function for each frame at the TS layer.

    Row() {
        Button('Start')
          .id('Start')
          .fontSize(14)
          .fontWeight(500)
          .margin({ bottom: 20, right: 6, left: 6 })
          .onClick(() => {
            if (this.xComponentContext1) {
              this.xComponentContext1.register();
            }
            if (this.xComponentContext2) {
              this.xComponentContext2.register();
            }
          })
          .width('30%')
          .height(40)
          .shadow(ShadowStyle.OUTER_DEFAULT_LG)
        
        Button('Stop')
          .id('Stop')
          .fontSize(14)
          .fontWeight(500)
          .margin({ bottom: 20, left: 6 })
          .onClick(() => {
            if (this.xComponentContext1) {
              this.xComponentContext1.unregister();
            }
            if (this.xComponentContext2) {
              this.xComponentContext2.unregister();
            }
          })
          .width('30%')
          .height(40)
          .shadow(ShadowStyle.OUTER_DEFAULT_LG)
    }