🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)
🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)

🔧 Programmierung 🕛 vor 2 Monaten 6 Min Lesezeit
0

How to implement two-way data synchronization between the app and the widget?

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

API comes in handy. This capability, when used in a widget, can start the specified UIAbility of the widget provider in the background. It also allows the widget to call the specified method of the application and transfer data so that the application, while in the background, can behave accordingly in response to touching the buttons on the widget.

  • The widget provider can call




    • MyModeCard




    CODE
    // mymode/pages/MyModeCard.ets

    import { Mode } from '../../model/Mode'

    let ls = new LocalStorage();

    @Entry(ls)
    @Component
    struct MyModeCard {
    @LocalStorageProp('mode') mode: Mode = Mode.happy

    build() {
    Row({ space: 8 }) {
    Button('😭')
    .fontSize(18)
    .backgroundColor(this.mode === Mode.sad ? Color.Red : Color.Grey)
    .type(ButtonType.Circle)
    .layoutWeight(1)
    .onClick(() => {
    this.changeMode(Mode.sad)
    })
    Button('😑')
    .fontSize(18)
    .backgroundColor(this.mode === Mode.neutral ? Color.Yellow : Color.Grey)
    .type(ButtonType.Circle)
    .layoutWeight(1)
    .onClick(() => {
    this.changeMode(Mode.neutral)
    })
    Button('😊')
    .fontSize(18)
    .backgroundColor(this.mode === Mode.happy ? Color.Green : Color.Grey)
    .type(ButtonType.Circle)
    .layoutWeight(1)
    .onClick(() => {
    this.changeMode(Mode.happy)
    })
    }
    .padding(8)
    .height('100%')
    .backgroundColor($r('sys.color.comp_background_primary'))
    .onClick(() => {
    postCardAction(this, {
    action: 'router',
    abilityName: 'EntryAbility',
    });
    })
    }

    changeMode(newMode: Mode) {
    if (this.mode !== newMode) {
    this.mode = newMode
    this.postCardActionCall(newMode)
    }
    }

    // call action to wake app
    postCardActionCall(newMode: Mode) {
    postCardAction(this, {
    action: 'call',
    abilityName: 'EntryAbility',
    params: {
    // function name
    method: 'changeMode',
    // additional parameters
    mode: newMode
    }
    });
    }
    }






    Step 5: Modify MyModeFormAbility to store widget IDs.




    • MyModeFormAbility




    CODE
    // mymodeformability/MyModeFormAbility.ets

    onAddForm(want: Want) {
    // Called to return a FormBindingData object.
    if (!want || !want.parameters) {
    console.error(`FormAbility onAddForm want or want.parameters is undefined`);
    return formBindingData.createFormBindingData('');
    }

    let formId: string = want.parameters[formInfo.FormParam.IDENTITY_KEY] as string;

    // store form id
    WidgetIdPrefs.addFormID(this.context, formId);
    console.log('set form id', formId)

    const data: ModeData = { mode: ModePrefs.getMode(this.context) };

    // send initial data to the widget
    return formBindingData.createFormBindingData(data);
    }

    onRemoveForm(formId: string) {
    // Called to notify the form provider that a specified form has been destroyed.
    // remove form id
    WidgetIdPrefs.removeFormID(this.context, formId);
    }






    Step 6: Modify Entrybility




    • to catch the call action.




    CODE
    // entryability/EntryAbility.ets

    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');

    // postCardAction 'call' is caught here
    this.callee.on('changeMode', (data: rpc.MessageSequence) => {
    // Obtain all parameters passed in the call event.
    const dataObj: ModeData = JSON.parse(data.readString())
    console.log('ModeData', JSON.stringify(dataObj), dataObj.mode);

    AppStorage.set('mode', dataObj.mode)
    ModePrefs.setMode(this.context, dataObj.mode);
    vibrator.startVibration({ type: 'time', duration: 200 }, { usage: 'physicalFeedback' })
    return new ModeParcelable(dataObj.mode);
    });
    }







    • to store mode in PersistentStorage (to update UI directly)




    CODE
    onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
    if (err.code) {
    hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
    return;
    }
    hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');

    const mode = ModePrefs.getMode(this.context)
    PersistentStorage.persistProp('mode', mode)
    AppStorage.set('mode', mode)
    });
    }






    Step 7: Modify Index.ets to show current mode.




    • Index




    CODE
    import { Mode } from '../model/Mode';
    import { ModeData } from '../model/ModeParcelable';
    import ModePrefs from '../util/ModePrefs';
    import WidgetIdPrefs from '../util/WidgetIdPrefs';
    import { formBindingData, formProvider } from '@kit.FormKit';


    @Entry
    @Component
    struct Index {
    @StorageLink('mode') mode: Mode = ModePrefs.getMode(this.getUIContext().getHostContext() as Context)

    build() {
    Row({ space: 8 }) {
    Button('😭')
    .fontSize(18)
    .backgroundColor(this.mode === Mode.sad ? Color.Red : Color.Grey)
    .type(ButtonType.Circle)
    .layoutWeight(1)
    .onClick(() => {
    this.changeMode(Mode.sad)
    })
    Button('😑')
    .fontSize(18)
    .backgroundColor(this.mode === Mode.neutral ? Color.Yellow : Color.Grey)
    .type(ButtonType.Circle)
    .layoutWeight(1)
    .onClick(() => {
    this.changeMode(Mode.neutral)
    })
    Button('😊')
    .fontSize(18)
    .backgroundColor(this.mode === Mode.happy ? Color.Green : Color.Grey)
    .type(ButtonType.Circle)
    .layoutWeight(1)
    .onClick(() => {
    this.changeMode(Mode.happy)
    })
    }
    .padding(8)
    .height('100%')
    .backgroundColor($r('sys.color.comp_background_primary'))
    }

    changeMode(newMode: Mode) {
    if (this.mode !== newMode) {
    this.mode = newMode
    ModePrefs.setMode(this.getUIContext().getHostContext() as Context, newMode)
    const ids = WidgetIdPrefs.getFormIDs(this.getUIContext().getHostContext() as Context)
    // update widgets
    ids.forEach((id: string) => {
    const data: ModeData = { 'mode': newMode }
    let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(data);
    formProvider.updateForm(id, formInfo)
    })
    }
    }
    }






    Step 8: Add a widget and see two-way synchronization.






    Written by Mehmet Karaaslan

    Vollständiger Original-Bericht
    Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
    ↗ Original-Artikel auf dev.to lesen
  • Wie bewertest du diesen Beitrag?
    1 Klick Feedback
    Teilen mit Netzwerk & Team:

    Community-Analysen & Experten-Meinungen 0

    Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
    Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
    Community Pulse: Relevanz-Einschätzung
    1 Klick Experten-Votum
    🔴 Akute Relevanz 0%
    🟡 In Evaluierung 0%
    🟢 Keine Auswirkung 0%
    Spannende Innovation 0%
    Verwandte Story-Cluster & Quellen (Vektor-KI)
    Port 8095 Engine
    1 Quelle
    Sam Altman calls GPT-6 Astra rollout ‘messy’ as enterprise users wait for access
    1 Quelle
    Swiss government explores replacing Microsoft 365 with open-source software
    1 Quelle
    What continuous operational resilience looks like under DORA
    Ähnliche Beiträge
    🔍 Verwandte News

    Auch interessante Nachrichten How to implement two-way data synchronization between the app and the widget?

    Thematisch verwandte Begriffe: implement, twoway, data, synchronization · 6 Treffer

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...