Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

HarmonyOS Stage Model: Card Data Interaction

Tech May 10 3

Through timed refresh and fixed-point refresh, developers can control the refresh frequency and timing of cards based on actual needs, thereby providing a better user experience.

2.1 Timed Refresh

{
  "forms": [
    {
      "name": "widget",
      "description": "This is a service widget.",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true,
      "scheduledUpdateTime": "10:30",
      "updateDuration": 2,
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"]
    }
  ]
}

Timed Refresh

2.2 Fixed-Point Refresh

{
  "forms": [
    {
      "name": "widget",
      "description": "This is a service widget.",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true,
      "scheduledUpdateTime": "10:30",
      "updateDuration": 0,
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"]
    }
  ]
}

Fixed-Point Refresh

2.3 Next Refresh

import formProvider from '@ohos.app.form.formProvider';

let formId = '123456789';
try {
  formProvider.setFormNextRefreshTime(formId, 5, (err, data) => {
    if (err) {
      console.error(`Failed to setFormNextRefreshTime. Code: ${err.code}, message: ${err.message}`);
      return;
    } else {
      console.info('Succeeded in setFormNextRefreshTimeing.');
    }
  });
} catch (err) {
  console.error(`Failed to setFormNextRefreshTime. Code: ${err.code}, message: ${err.message}`);
}

For specific refresh methods, refer to the previous article.

3. Refreshing Local and Network Images

In HarmonyOS card development, images can be displayed by requesting local images and network images.

Requesting local images can use HarmonyOS's resource manager to obtain local image resources and display them on the card.

First, enable the following permission:

ohos.permission.INTERNET

3.1 Sending Local Images

import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import request from '@ohos.request';
import fs from '@ohos.file.fs';

export default class EntryFormAbility extends FormExtensionAbility {
  // When adding a card, open a local image and pass the image content to the card page
  onAddForm(want) {
    let tempDir = this.context.getApplicationContext().tempDir;
    let file;
    try {
      file = fs.openSync(tempDir + '/' + 'head.PNG');
    } catch (e) {
      console.error(`openSync failed: ${JSON.stringify(e)}`);
    }
    let formData = {
      'text': 'Image: Bear',
      'imgName': 'imgBear',
      'formImages': {
        'imgBear': file.fd
      },
      'loaded': true
    };
    return formBindingData.createFormBindingData(formData);
  }
}

3.2 Sending Network Images

import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import request from '@ohos.request';
import fs from '@ohos.file.fs';

export default class EntryFormAbility extends FormExtensionAbility {
  onFormEvent(formId, message) {
    let formInfo = formBindingData.createFormBindingData({
      'text': 'Refreshing...'
    });
    formProvider.updateForm(formId, formInfo);
    // Note: FormExtensionAbility is only available for 5 seconds in the background when triggered
    // It is recommended to download small files that can be downloaded quickly
    let netFile = 'https://xxxx/xxxx.png';
    let tempDir = this.context.getApplicationContext().tempDir;
    let tmpFile = tempDir + '/file' + Date.now();
    request.downloadFile(this.context, {
      url: netFile, filePath: tmpFile
    }).then((task) => {
      task.on('complete', function callback() {
        console.info('ArkTSCard download complete:' + tmpFile);
        let file;
        try {
          file = fs.openSync(tmpFile);
        } catch (e) {
          console.error(`openSync failed: ${JSON.stringify(e)}`);
        }
        let formData = {
          'text': 'Image: Https',
          'imgName': 'imgHttps',
          'formImages': {
            'imgHttps': file.fd
          },
          'loaded': true
        };
        let formInfo = formBindingData.createFormBindingData(formData);
        formProvider.updateForm(formId, formInfo).then((data) => {
          console.info('FormAbility updateForm success.' + JSON.stringify(data));
        }).catch((error) => {
          console.error('FormAbility updateForm failed: ' + JSON.stringify(error));
        });
      });
      task.on('fail', function callBack(err) {
        console.info('ArkTSCard download task failed. Cause:' + err);
        let formInfo = formBindingData.createFormBindingData({
          'text': 'Refresh failed'
        });
        formProvider.updateForm(formId, formInfo);
      });
    }).catch((err) => {
      console.error('Failed to request the download. Cause: ' + JSON.stringify(err));
    });
  }
}

3.3 Card UI Recieving Data

let storage = new LocalStorage();

@Entry(storage)
@Component
struct WidgetCard {
  @LocalStorageProp('text') text: string = 'Loading...';
  @LocalStorageProp('loaded') loaded: boolean = false;
  @LocalStorageProp('imgName') imgName: string = 'name';

  build() {
    Column() {
      Text(this.text)
        .fontSize('12vp')
        .textAlign(TextAlign.Center)
        .width('100%')
        .height('15%');

      Row() {
        if (this.loaded) {
          Image('memory://' + this.imgName)
            .width('50%')
            .height('50%')
            .margin('5%');
        } else {
          Image('common/start.PNG')
            .width('50%')
            .height('50%')
            .margin('5%');
        }
      }.alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.Center);

      Button('Refresh')
        .height('15%')
        .onClick(() => {
          postCardAction(this, {
            'action': 'message',
            'params': {
              'info': 'refreshImage'
            }
          });
        });
    }
    .width('100%').height('100%')
    .alignItems(HorizontalAlign.Center)
    .padding('5%');
  }
}

4. Refreshing Different Content Based on Card State

We can add two desktop cards: one displaying weather in Hangzhou, and another displaying weather in Beijing. These cards can trigger a timed refresh every morning at 7:00. The card needs to know its current configuration (Hangzhou or Beijing) and refresh accordingly. The following example demonstrates how to dynamically select content to refresh based on the card's state.

  1. Configure timed refresh:
{
  "forms": [
    {
      "name": "widget",
      "description": "This is a service widget.",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true,
      "scheduledUpdateTime": "07:00",
      "updateDuration": 0,
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"]
    }
  ]
}
  1. Select state:
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
  @LocalStorageProp('textA') textA: string = 'Pending refresh...';
  @LocalStorageProp('textB') textB: string = 'Pending refresh...';
  @State selectA: boolean = false;
  @State selectB: boolean = false;

  build() {
    Column() {
      Row() {
        Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
          .select(false)
          .onChange((value: boolean) => {
            this.selectA = value;
            postCardAction(this, {
              'action': 'message',
              'params': {
                'selectA': JSON.stringify(value)
              }
            });
          });
        Text('State A');
      }

      Row() {
        Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
          .select(false)
          .onChange((value: boolean) => {
            this.selectB = value;
            postCardAction(this, {
              'action': 'message',
              'params': {
                'selectB': JSON.stringify(value)
              }
            });
          });
        Text('State B');
      }

      Row() {
        Text('State A: ');
        Text(this.textA);
      }

      Row() {
        Text('State B: ');
        Text(this.textB);
      }
    }.padding('10%');
  }
}
  1. Refresh content based on state (continuing from the previous code):
import formInfo from '@ohos.app.form.formInfo';
import formProvider from '@ohos.app.form.formProvider';
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import dataStorage from '@ohos.data.storage';

export default class EntryFormAbility extends FormExtensionAbility {
  onAddForm(want) {
    let formId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
    let isTempCard: boolean = want.parameters[formInfo.FormParam.TEMPORARY_KEY];
    if (isTempCard === false) {
      console.info('Not temp card, init db for:' + formId);
      // Persistence logic here
    }
  }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.