ArkTS and OpenHarmony Development Reference: Language Features and Runtime Behaviors
UI Builder Function Constraints in ArkTS
The build() method and custom builder functions operate under strict compilation rules to ensure predictable UI rendering. Expressions are restricted to string interpolation, conditional rendering, ForEach iterators, and component properties. Modifying application state variables (e.g., @State, @Prop, @Link) within these expressions is prohibited, as it triggers undefined framework behavior. Local variable declarations and arbitrary function invocations are also blocked inside the builder scope, except for event handlers like onClick.
build() {
// let counter = 0; // Compilation error: local variables forbidden
Column() {
Text(`User: ${this.profile.name.toUpperCase()}`) // Valid interpolation
// ForEach(this.items.sort(), ...) // Error: mutates @State array
ForEach(this.items.slice(), (item: string) => {
Text(item)
})
// this.runLogic(); // Error: direct calls not allowed
Text(this.formatLabel()) // Valid: returns computed string
}
}
Dynamic Placeholder Replacement in String Resources
Application resources referenced via $r() support runtime parameter injection. Pass additional arguments to $r() to replace %s tokens defined in the string.json configuration.
build() {
Text($r('app.string.welcome_msg', 'Guest_User'))
.fontSize(24)
.fontColor('#000000')
}
Reading Raw Files and Converting to Strings
To process raw assets like XML configurations, retrieve the file as a Uint8Array through the resource manager, then decode it using standard JavaScript character conversion methods.
resourceManager.getRawFile('config/data.xml', (err, buffer) => {
if (err) {
console.error(`Failed to load asset: ${err.message}`);
return;
}
const xmlContent = String.fromCharCode.apply(null, buffer);
console.info(xmlContent);
});
Extracting String Values from Resource Objects
When a resource ID object is available, resolve its actual string value by invoking resourceManager.getString() with the resource identifier.
Static Class Properties vs. Global State
Pages and Abilities are bundled into isolated closures during compilation, resulting in separate global execution contexts. Consequently, static class properties do not share references across different UI modules. For cross-component state sharing, utilize AppStorage or LocalStorage instead of static class fields.
Resource Access via Context in Stage Model
The Stage architecture exposes a resourceManager instance directly through the UI context. This eliminates the need for explicit module imports when fetching localized assets.
const uiContext = getContext(this) as common.UIAbilityContext;
uiContext.resourceManager.getString($r('app.string.hello').id)
.then((res) => {
this.displayText = res;
})
.catch((err) => console.error(err));
Asynchronous Data Initialization Before Rendering
Trigger network requests or async operations inside the aboutToAppear lifecycle hook. Bind the result to a @State variable to automatically trigger UI updates once the data resolves.
@Entry
@Component
struct DataSyncView {
@State statusText: string = 'Initializing...';
aboutToAppear() {
setTimeout(() => {
this.statusText = 'Sync Complete';
}, 2000);
}
build() {
Column() {
Text(this.statusText).fontSize(20)
}.width('100%').height('100%')
}
}
Worker Thread Execution Context
Background workers operate in isolated V8 instances separate from the main UI thread. Direct memory sharing is unsupported; all data exchange must occur via message passing APIs.
URI Encoding and Decoding
Standard global functions encodeURI() and decodeURI() handle URL-safe string transformation. Whitespace and special characters are converted to their percent-encoded equivalents (e.g., space becomes %20).
XML Document Parsing
Transform XML markup into traversable JavaScript objects using the convertXML.convert() utility provided by the framework.
Adaptive Application Icons
Leverage resource qualifiers to define multiple icon assets. The system automatically selects the appropriate resolution and theme variant based on device capabilities and user settings.
System Time Precision APIs
systemTime.getCurrentTime(false) aligns with new Date().getTime(), returning milliseconds since the Unix epoch. Passing true yields nanosecond precision. Both query the underlying system clock.
Typing Rules for @BuilderParam
When assigning a builder reference without invocation (e.g., slot: this.renderHeader), declare the property as a void function: @BuilderParam slot: () => void. If invoking with arguments during assignment (e.g., slot: this.renderHeader('title')), type the property as any to accommodate the evaluated result.
Worker Pool Limits and Cleanup
The runtime enforces a hard limit of seven concurrent worker instances per application. Exceeding this threshold throws a capacity exception. Always invoke worker.terminate() when background tasks complete to free execution slots.
Recommended Concurrency Model
For CPU-intensive operations or non-blocking I/O, the framework officially endorses the Worker API over traditional threading mechanisms to maintain UI responsiveness.
Component Re-instantiation in @Builder Methods
Decorated builder functions that instantiate custom components will generate fresh component instances on every invocation. This behavior differs from standard utility methods and impacts rendering performance if overused.
State Observation Depth and @Watch
The @Watch decorator monitors shallow reference changes only. Mutations to nested object properties or array elements do not trigger callbacks, mirroring the baseline behavior of @State.
Deep Reactive State Tracking
To observe mutations within complex objects or arrays, decorate the data model with @Observed and bind it to the UI using @ObjectLink. This enables granular change detection for nested structures.
Text Encoding and Decoding Utilities
Convert between byte streams and string representations using the TextEncoder and TextDecoder classes available in the util module.
Namespace Module Export Patterns
Group related utilities under a namespace and export them as a default module for cleaner imports.
namespace DateUtils {
export function now(): number {
return Date.now();
}
}
export default DateUtils;
import DateUtils from './utils/date';
const timestamp = DateUtils.now();
Relational Database Access in Workers
RDB connection objects created on the main thread cannot be serialized or transferred to worker threads. Background tasks must initialize their own independent database connections using the relational store APIs.