This content originally appeared on DEV Community and was authored by kouwei qing
[Daily HarmonyOS Next Knowledge] Extending to Status Bar, Global Storage Issues, State Variable Collaboration, Refresh Component Usage, Scrolling to Fixed Position
1. HarmonyOS: Page top extension to status bar is ineffective?
Refer to the demo:
@Entry
@Component
struct Index {
build() {
Swiper() {
Column() {
Image($r('app.media.background'))
.height('50%').width('100%')
// Set image to extend to status bar
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
Column() {
Text('HarmonyOS 第一课')
.fontSize(32)
.margin(30)
Text('Through a gradual learning path, both inexperienced and experienced developers can master the ArkTS declarative development paradigm and experience a simpler and more friendly HarmonyOS application development journey.')
.fontSize(20).margin(20)
}.height('50%').width('100%')
.backgroundColor(Color.White)
// Set text content area background to extend to navigation bar
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
}
}
.width('100%')
.height('100%')
// Disable the default clipping effect of the Swiper component to allow child nodes to draw outside the Swiper.
.clip(false)
}
}
2. How much information can HarmonyOS AppStorage store?
- The project needs to store user information and uses AppStorage for storage. After logging in, the information can be retrieved via AppStorage.get. However, when the app is reopened, the data cannot be obtained directly. Is it because too much information is stored to retrieve?
- If this is not feasible, what storage methods can be used?
This issue occurs because each IDE compilation is equivalent to uninstalling and reinstalling the app, and previously flushed data is cleared with the app during uninstallation. Thus, data flushed before cannot be queried after the second compilation. This does not affect data flushing in normal user scenarios. Simply check Keep Application Data in the IDE.
AppStorage is not persistent storage. For persistent storage, use PersistentStorage. PersistentStorage variables should preferably be less than 2KB; avoid persisting large data volumes because disk writes in PersistentStorage are synchronous, and extensive local read/write operations execute on the UI thread, affecting UI rendering performance. For large data storage, use database APIs. Related documentation: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-persiststorage-V5
Both LocalStorage and AppStorage are runtime memories, but they can retain selected results after the app restarts, a common requirement in app development. PersistentStorage, an optional singleton in the app, persists selected AppStorage attributes to ensure their values remain unchanged between app restarts.
PersistentStorage saves selected AppStorage attributes to device disk. The app uses APIs to determine which AppStorage attributes to persist via PersistentStorage. UI and business logic do not directly access PersistentStorage attributes; all access occurs through AppStorage, with changes automatically synced to PersistentStorage.
PersistentStorage and AppStorage establish bidirectional synchronization for attributes. App development typically accesses PersistentStorage via AppStorage, with additional interfaces for managing persistent attributes, though business logic always retrieves and sets attributes through AppStorage.
3. How does HarmonyOS @Sendable work with @ObservedV2?
Currently, a class cannot support both @Sendable and @ObservedV2. An object cannot be both a multi-thread shared object and an observable object.
Based on the issue that @Sendable and @ObservedV2 cannot be mixed, two solutions are provided:
- Whole tracking of Sendable objects (sample code):
import taskpool from '@ohos.taskpool';
import { SendableData } from './SendableData';
@Concurrent
function threadGetData(param: string): SendableData {
let ret = new SendableData()
ret.name = param + "-o"
ret.age = Math.floor(Math.random() * 40)
ret.likes = Math.floor(Math.random() * 100)
return ret // Return a new SendableData instance
}
@ObservedV2
class ViewModelWithSendable {
@Trace data?: SendableData // Track the entire object with @Trace
@Trace sendParam: string = "chen"
runTask() {
taskpool.execute(threadGetData, this.sendParam).then((value: object) => {
this.data = value as SendableData // Replace the entire data object
this.sendParam = this.data.name
})
}
}
@Entry
@Component
struct Index {
mySendData: ViewModelWithSendable = new ViewModelWithSendable()
build() {
Column() {
Text(`SendParam=${this.mySendData.sendParam}`).fontSize(30).fontColor(Color.Red)
Button("runTask").onClick(this.mySendData.runTask.bind(this.mySendData))
if (this.mySendData.data) {
Row() {
Text(this.mySendData.data.name).fontSize(30).layoutWeight(4)
Text(this.mySendData.data.age.toString()).fontSize(30).fontColor(Color.Blue).layoutWeight(1)
Text(this.mySendData.data.likes.toString()).fontSize(30).fontColor(Color.Green).layoutWeight(1)
Text(this.mySendData.data.follow ? "已关注" : "关注").fontSize(30).fontColor(Color.Green).layoutWeight(2)
}
}
}
}
}
- Partial update of Sendable objects (sample code):
import taskpool from '@ohos.taskpool';
import { SendableData } from './SendableData';
@Concurrent
function threadLike(param: SendableData): boolean {
param.likes++
return true
}
@Concurrent
function threadFollow(param: SendableData): boolean {
param.likes++
return true
}
@Concurrent
function threadReset(param: SendableData): boolean {
let likes: number = param.likes
// .....
return true
}
@ObservedV2
class ViewModelWithSendable {
data: SendableData = new SendableData() // No need to track overall changes
@Trace sendParam: string = "chen"
@Trace likes: number = 0 // Define responsive data
@Trace follow: boolean = false // Define responsive data
iLike() {
taskpool.execute(threadLike, this.data).then((value: object) => {
this.likes = this.data.likes // Assign only changed properties for UI refresh
})
}
iFollow() {
taskpool.execute(threadFollow, this.data).then((value: object) => {
this.follow = this.data.follow // Assign only changed properties for UI refresh
})
}
reset() {
// Update data first, then refresh the UI, and then use the thread to work
this.likes = 0
this.data.likes = this.likes
this.follow = false
this.data.follow = this.follow
taskpool.execute(threadReset, this.data)
}
}
@Entry
@Component
struct Index {
mySendData: ViewModelWithSendable = new ViewModelWithSendable()
build() {
Column() {
Row() {
Button("Like").onClick(this.mySendData.iLike.bind(this.mySendData))
Button("Follow").onClick(this.mySendData.iFollow.bind(this.mySendData))
Button("Reset").onClick(this.mySendData.reset.bind(this.mySendData))
}
Row() {
Text(this.mySendData.data.name).fontSize(30).layoutWeight(4)
Text(this.mySendData.data.age.toString()).fontSize(30).fontColor(Color.Blue).layoutWeight(1)
Text(this.mySendData.data.likes.toString()).fontSize(30).fontColor(Color.Green).layoutWeight(1)
Text(this.mySendData.data.follow ? "已关注" : "关注").fontSize(30).fontColor(Color.Green).layoutWeight(2)
}
}
}
}
4. HarmonyOS Refresh component usage issues?
- After setting the LoadingProgress height, part of it is exposed without scrolling.
- Expect that when quickly scrolling from the bottom to the top, the Builder does not actively display.
Add the .clip(true)
attribute. Specific demo:
@Entry
@Component
struct Index {
@State isRefreshing: boolean = false
@State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
@Builder
refreshComponent() {
Stack() {
Row() {
LoadingProgress()
.height(32)
.width(40)
.color(Color.Red)
Text("正在刷新...")
.fontSize(16)
.margin({ left: 20 })
}
.clip(true)
.alignItems(VerticalAlign.Center)
}.width("100%").align(Alignment.Center)
}
build() {
Stack({ alignContent: Alignment.TopStart }) {
Flex({ direction: FlexDirection.Column }) {
Refresh({
refreshing: $$this.isRefreshing,
builder: this.refreshComponent()
}) {
Scroll() {
Column() {
ForEach(this.arr, (item: string) => {
Text('' + item)
.width('100%')
.height(100)
.fontSize(16)
.textAlign(TextAlign.Center)
.borderRadius(10)
}, (item: string) => item)
}
}
}
.onStateChange((refreshStatus: RefreshStatus) => {
console.info('Refresh onStatueChange state is ' + refreshStatus)
})
.onRefreshing(() => {
setTimeout(() => {
this.isRefreshing = false
}, 2000)
console.log('onRefreshing test')
})
}
}
}
}
5. HarmonyOS list scrollToIndex?
When scrolling a List to a specified index with multiple ListItemGroups (each containing multiple ListItems), which index should be specified for scrollToIndex?
Use scrollToItemInGroup
to scroll to a specified ListItem in a ListItemGroup. Refer to: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-list-V5#scrolltoitemingroup11
scrollToItemInGroup(index: number, indexInGroup: number, smooth?: boolean, align?: ScrollAlign): void
Scrolls to a specified ListItem in a ListItemGroup.
Enabling smooth animation triggers loading and layout calculations for all passed items, potentially causing performance issues with large item counts.
Parameters:
Parameter Name | Type | Required | Description |
---|---|---|---|
index | number | Yes | The index of the target ListItemGroup in the current container. Note: Negative values or values greater than the maximum index of child components are invalid, and the jump does not take effect. |
indexInGroup | number | Yes | The index of the target ListItem within the specified ListItemGroup. Note: Negative values or values greater than the maximum index of child components in the ListItemGroup are invalid, and the jump does not take effect. |
smooth | boolean | No | Whether to enable animation when scrolling to the list item. true enables animation, false disables it.Default: false . |
align | ScrollAlign | No | Specifies the alignment of the scrolled element with the current container. Default: ScrollAlign.START . |
This content originally appeared on DEV Community and was authored by kouwei qing

kouwei qing | Sciencx (2025-06-28T12:19:54+00:00) Extending to Status Bar, Global Storage Issues, State Variable Collaboration, Refresh Component Usage. Retrieved from https://www.scien.cx/2025/06/28/extending-to-status-bar-global-storage-issues-state-variable-collaboration-refresh-component-usage/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.