首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >HarmonyOS应用开发实战 | ArkTS 网络连接管理使用指南(精品篇)

HarmonyOS应用开发实战 | ArkTS 网络连接管理使用指南(精品篇)

作者头像
红目香薰
发布2025-12-16 17:06:54
发布2025-12-16 17:06:54
190
举报
文章被收录于专栏:CSDNToQQCodeCSDNToQQCode

? 红目香薰 倾情分享 ? 用心打造每一个技术细节,为开发者创造更多价值 ? 让HarmonyOS开发变得更简单、更有趣


✨ 写在前面的话

嗨,亲爱的技术朋友们!?

我是红目香薰,一个热爱技术、专注HarmonyOS开发的程序媛。在这个数字化飞速发展的时代,HarmonyOS作为华为自主研发的操作系统,正在改变着我们的数字生活体验。

? 为什么要写这个系列?

  • ? 让复杂的技术变得简单易懂
  • ? 帮助更多开发者快速上手HarmonyOS
  • ? 分享实战经验,避免踩坑
  • ? 用代码创造美好,用技术传递温暖

每一个Demo都是我精心设计和反复测试的结果,希望能够为你的HarmonyOS开发之路点亮一盏明灯。✨

今天我们来深入学习HarmonyOS中最重要的网络功能之一——网络连接管理。从基础的HTTP请求到复杂的网络状态监控,让我们一起打造稳定可靠的网络应用!


? Demo功能说明

img
img
? 核心功能

本Demo展示了HarmonyOS中网络连接管理的全面使用方法,包括:

  • ? HTTP请求的发送和响应处理
  • ? 网络状态监控和连接管理
  • ? 请求重试机制和错误处理
  • ? 网络数据缓存和离线支持
  • ? 加载状态和错误提示的UI展示
  • ? 网络安全和数据加密处理
  • ⚡ 并发请求管理和性能优化
  • ? 实际应用场景的完整实现
✨ 特色亮点
  • ? 视觉精美:现代化的加载动画和状态提示
  • ? 性能优秀:智能缓存和请求优化机制
  • ? 用户友好:清晰的错误提示和重试机制
  • ? 功能完整:涵盖网络应用的各种场景
  • ? 实用性强:可直接应用于实际项目开发
? 界面展示

界面采用现代化的网络应用设计:

  • 诗词查询:输入关键词获取相关诗词
  • 网络状态:实时显示网络连接状态
  • 请求历史:展示历史请求记录
  • 缓存管理:本地数据缓存和清理
  • 设置页面:网络相关配置选项
? 适用场景
  • ? 新闻应用的内容获取和更新
  • ?️ 电商应用的商品数据加载
  • ? 社交应用的消息同步和推送
  • ? 数据应用的实时信息获取
  • ? 音视频应用的流媒体播放
  • ?️ 天气应用的实时数据更新

? 核心代码说明

? 项目结构
代码语言:javascript
复制
NetworkDemo/
├── src/
│   ├── main/
│   │   ├── ets/
│   │   │   ├── pages/
│   │   │   │   └── Index.ets          // 主页面
│   │   │   ├── utils/
│   │   │   │   ├── HttpUtil.ets       // 网络工具类
│   │   │   │   └── CacheUtil.ets      // 缓存工具类
│   │   │   └── entryability/
│   │   └── resources/
│   │       ├── base/
│   │       │   ├── element/
│   │       │   └── media/
│   │       └── rawfile/
│   └── module.json5
? 关键技术点
1. HTTP请求基础结构
代码语言:javascript
复制
import http from '@ohos.net.http';

// 创建HTTP请求
let httpRequest = http.createHttp();
httpRequest.request(url, {
  method: http.RequestMethod.GET,
  header: {
    'Content-Type': 'application/json'
  }
});
2. 网络状态监控
代码语言:javascript
复制
import connection from '@ohos.net.connection';

// 监听网络状态变化
connection.on('netConnectionChange', (data) => {
  console.log('Network status changed:', data);
});
3. 请求拦截和处理
代码语言:javascript
复制
// 请求拦截器
const interceptRequest = (config: RequestConfig) => {
  // 添加通用请求头
  config.header = {
    ...config.header,
    'Authorization': 'Bearer token'
  };
  return config;
};
4. 错误处理机制
  • 网络错误:连接超时、DNS解析失败
  • HTTP错误:4xx客户端错误、5xx服务器错误
  • 数据错误:JSON解析失败、数据格式错误
? 技术要点解析

请求生命周期管理: 从请求发起到响应处理的完整生命周期管理,包括加载状态、成功回调、错误处理。

智能缓存策略: 根据数据特性和用户行为,实现智能的缓存策略,提升用户体验和应用性能。

网络优化技术: 通过请求合并、数据压缩、连接复用等技术优化网络性能。


? 完整Demo代码

? 主页面代码
代码语言:javascript
复制
// src/main/ets/pages/Index.ets

import http from '@ohos.net.http';
import connection from '@ohos.net.connection';
import { BusinessError } from '@ohos.base';

// 诗词数据接口
interface PoetryData {
  title: string
  name: string
  content: string
}

// 网络状态接口
interface NetworkStatus {
  isConnected: boolean
  networkType: string
  signalStrength: number
}

// 请求历史接口
interface RequestHistory {
  id: number
  keyword: string
  timestamp: number
  success: boolean
  responseTime: number
}

// 缓存数据接口
interface CacheData {
  key: string
  data: PoetryData[]
  timestamp: number
  expireTime: number
}

@Entry
@Component
struct NetworkDemo {
  @State currentTab: number = 0
  @State searchKeyword: string = ''
  @State poetryList: PoetryData[] = []
  @State isLoading: boolean = false
  @State errorMessage: string = ''
  @State networkStatus: NetworkStatus = {
    isConnected: true,
    networkType: 'WiFi',
    signalStrength: 100
  }
  @State requestHistory: RequestHistory[] = []
  @State cacheList: CacheData[] = []

  private httpRequest: http.HttpRequest = http.createHttp()
  private readonly API_BASE_URL = 'http://39.107.126.100:5000/api/infos'
  private readonly CACHE_EXPIRE_TIME = 5 * 60 * 1000 // 5分钟缓存

  aboutToAppear() {
    this.initNetworkMonitoring()
    this.loadCacheData()
    this.loadRequestHistory()
  }

  aboutToDisappear() {
    this.httpRequest.destroy()
  }

  build() {
    Column() {
      this.buildHeader()
      Tabs({ barPosition: BarPosition.End, index: this.currentTab }) {
        TabContent() {
          this.buildSearchPage()
        }
        .tabBar(this.buildTabBar(0, '诗词查询', '?'))

        TabContent() {
          this.buildNetworkStatusPage()
        }
        .tabBar(this.buildTabBar(1, '网络状态', '?'))

        TabContent() {
          this.buildHistoryPage()
        }
        .tabBar(this.buildTabBar(2, '请求历史', '?'))

        TabContent() {
          this.buildCachePage()
        }
        .tabBar(this.buildTabBar(3, '缓存管理', '?'))
      }
      .layoutWeight(1)
      .barBackgroundColor('#FFFFFF')
      .barHeight(80)
      .animationDuration(300)
      .onChange((index: number) => {
        this.currentTab = index
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  @Builder
  buildHeader() {
    Row({ space: 15 }) {
      Text('?')
        .fontSize(24)
      Text('网络连接管理示例')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .layoutWeight(1)
      Stack({ alignContent: Alignment.TopEnd }) {
        Text('?')
          .fontSize(20)
          .fontColor(Color.White)
        if (!this.networkStatus.isConnected) {
          Text('!')
            .fontSize(12)
            .fontColor('#FF4444')
            .backgroundColor(Color.White)
            .borderRadius(6)
            .padding({ left: 3, right: 3 })
            .margin({ top: -2, right: -2 })
        }
      }
    }
    .width('100%')
    .height(60)
    .padding({ left: 20, right: 20 })
    .backgroundColor('#667eea')
    .shadow({
      radius: 8,
      color: '#30000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildTabBar(index: number, title: string, icon: string) {
    Column({ space: 5 }) {
      Stack({ alignContent: Alignment.TopEnd }) {
        Text(icon)
          .fontSize(24)
          .fontColor(this.currentTab === index ? '#667eea' : '#999999')
        if (index === 2 && this.requestHistory.length > 0) {
          Text(this.requestHistory.length.toString())
            .fontSize(10)
            .fontColor(Color.White)
            .backgroundColor('#FF4444')
            .borderRadius(8)
            .padding({ left: 4, right: 4, top: 1, bottom: 1 })
            .margin({ top: -5, right: -5 })
        }
      }
      Text(title)
        .fontSize(12)
        .fontColor(this.currentTab === index ? '#667eea' : '#999999')
        .fontWeight(this.currentTab === index ? FontWeight.Medium : FontWeight.Normal)
    }
    .width(60)
    .height(60)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  buildSearchPage() {
    Column({ space: 20 }) {
      this.buildSearchInput()
      if (this.isLoading) {
        this.buildLoadingView()
      } else if (this.errorMessage) {
        this.buildErrorView()
      } else if (this.poetryList.length > 0) {
        this.buildPoetryList()
      } else {
        this.buildEmptyView()
      }
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }

  @Builder
  buildSearchInput() {
    Column({ space: 15 }) {
      Text('? 诗词搜索')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
        .alignSelf(ItemAlign.Start)

      Row({ space: 10 }) {
        TextInput({ placeholder: '请输入关键词,如:梅花香自苦寒来' })
          .layoutWeight(1)
          .height(50)
          .borderRadius(25)
          .backgroundColor(Color.White)
          .padding({ left: 20, right: 20 })
          .onChange((value: string) => {
            this.searchKeyword = value
          })
          .onSubmit(() => {
            this.searchPoetry()
          })

        Button('搜索')
          .width(80)
          .height(50)
          .borderRadius(25)
          .backgroundColor('#667eea')
          .fontColor(Color.White)
          .enabled(!this.isLoading && this.searchKeyword.length > 0)
          .onClick(() => {
            this.searchPoetry()
          })
      }

      Row({ space: 10 }) {
        Text('热门搜索:')
          .fontSize(14)
          .fontColor('#666666')

        Button('春花秋月')
          .height(30)
          .fontSize(12)
          .backgroundColor('#E8F4FD')
          .fontColor('#667eea')
          .borderRadius(15)
          .onClick(() => {
            this.searchKeyword = '春花秋月'
            this.searchPoetry()
          })

        Button('山水田园')
          .height(30)
          .fontSize(12)
          .backgroundColor('#E8F4FD')
          .fontColor('#667eea')
          .borderRadius(15)
          .onClick(() => {
            this.searchKeyword = '山水田园'
            this.searchPoetry()
          })

        Button('离别相思')
          .height(30)
          .fontSize(12)
          .backgroundColor('#E8F4FD')
          .fontColor('#667eea')
          .borderRadius(15)
          .onClick(() => {
            this.searchKeyword = '离别相思'
            this.searchPoetry()
          })
      }
      .width('100%')
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildLoadingView() {
    Column({ space: 20 }) {
      LoadingProgress()
        .width(50)
        .height(50)
        .color('#667eea')
      Text('正在搜索诗词...')
        .fontSize(16)
        .fontColor('#666666')
      Text('请稍候,我们正在为您查找相关内容')
        .fontSize(14)
        .fontColor('#999999')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height(200)
    .justifyContent(FlexAlign.Center)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildErrorView() {
    Column({ space: 20 }) {
      Text('❌')
        .fontSize(60)
      Text('请求失败')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FF4444')
      Text(this.errorMessage)
        .fontSize(14)
        .fontColor('#666666')
        .textAlign(TextAlign.Center)
        .maxLines(3)
      Button('重试')
        .backgroundColor('#667eea')
        .borderRadius(20)
        .onClick(() => {
          this.searchPoetry()
        })
    }
    .width('100%')
    .height(200)
    .justifyContent(FlexAlign.Center)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildEmptyView() {
    Column({ space: 20 }) {
      Text('?')
        .fontSize(60)
      Text('开始搜索')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
      Text('输入关键词,探索中华诗词的魅力')
        .fontSize(14)
        .fontColor('#666666')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height(200)
    .justifyContent(FlexAlign.Center)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildPoetryList() {
    Column({ space: 15 }) {
      Row() {
        Text(`? 搜索结果 (${this.poetryList.length}条)`)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
          .layoutWeight(1)
        Text('清空')
          .fontSize(14)
          .fontColor('#667eea')
          .onClick(() => {
            this.poetryList = []
            this.errorMessage = ''
          })
      }
      .width('100%')

      List({ space: 10 }) {
        ForEach(this.poetryList, (poetry: PoetryData, index: number) => {
          ListItem() {
            this.buildPoetryCard(poetry, index)
          }
        })
      }
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .layoutWeight(1)
  }

  @Builder
  buildPoetryCard(poetry: PoetryData, index: number) {
    Column({ space: 15 }) {
      Row({ space: 10 }) {
        Text(`${index + 1}`)
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .backgroundColor('#667eea')
          .borderRadius(15)
          .width(30)
          .height(30)
          .textAlign(TextAlign.Center)
        Column({ space: 5 }) {
          Text(poetry.title)
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .fontColor('#333333')
            .alignSelf(ItemAlign.Start)
          Text(`作者:${poetry.name}`)
            .fontSize(14)
            .fontColor('#666666')
            .alignSelf(ItemAlign.Start)
        }
        .alignItems(HorizontalAlign.Start)
        .layoutWeight(1)
        Text('?')
          .fontSize(20)
          .onClick(() => {
            console.log('收藏诗词:', poetry.title)
          })
      }
      .width('100%')

      Text(poetry.content)
        .fontSize(16)
        .fontColor('#333333')
        .lineHeight(28)
        .backgroundColor('#F8F9FA')
        .borderRadius(10)
        .padding(15)
        .width('100%')

      Row({ space: 15 }) {
        Button('分享')
          .height(35)
          .fontSize(12)
          .backgroundColor('#E8F4FD')
          .fontColor('#667eea')
          .borderRadius(17)
          .onClick(() => {
            console.log('分享诗词:', poetry.title)
          })
        Button('复制')
          .height(35)
          .fontSize(12)
          .backgroundColor('#E8F4FD')
          .fontColor('#667eea')
          .borderRadius(17)
          .onClick(() => {
            console.log('复制诗词:', poetry.content)
          })
        Button('详情')
          .height(35)
          .fontSize(12)
          .backgroundColor('#E8F4FD')
          .fontColor('#667eea')
          .borderRadius(17)
          .onClick(() => {
            console.log('查看详情:', poetry.title)
          })
      }
      .justifyContent(FlexAlign.Start)
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildNetworkStatusPage() {
    Scroll() {
      Column({ space: 20 }) {
        this.buildNetworkStatusCard()
        this.buildNetworkTestCard()
        this.buildNetworkSettingsCard()
      }
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }

  @Builder
  buildNetworkStatusCard() {
    Column({ space: 20 }) {
      Row() {
        Text('? 网络状态')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
          .layoutWeight(1)
        Text(this.networkStatus.isConnected ? '已连接' : '未连接')
          .fontSize(14)
          .fontColor(this.networkStatus.isConnected ? '#27AE60' : '#FF4444')
          .backgroundColor(this.networkStatus.isConnected ? '#E8F8F5' : '#FFEBEE')
          .padding({ left: 10, right: 10, top: 5, bottom: 5 })
          .borderRadius(12)
      }
      .width('100%')

      Column({ space: 15 }) {
        this.buildStatusItem('网络类型', this.networkStatus.networkType, '?')
        this.buildStatusItem('信号强度', `${this.networkStatus.signalStrength}%`, '?')
        this.buildStatusItem('连接状态', this.networkStatus.isConnected ? '正常' : '断开', '?')
        this.buildStatusItem('DNS状态', '正常', '?')
      }

      Button('刷新状态')
        .width('100%')
        .height(45)
        .backgroundColor('#667eea')
        .borderRadius(22)
        .onClick(() => {
          this.checkNetworkStatus()
        })
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildNetworkTestCard() {
    Column({ space: 20 }) {
      Text('? 网络测试')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
        .alignSelf(ItemAlign.Start)

      Grid() {
        GridItem() {
          this.buildTestButton('连通性测试', '?', () => {
            this.testConnectivity()
          })
        }
        GridItem() {
          this.buildTestButton('速度测试', '⚡', () => {
            this.testSpeed()
          })
        }
        GridItem() {
          this.buildTestButton('延迟测试', '⏱️', () => {
            this.testLatency()
          })
        }
        GridItem() {
          this.buildTestButton('DNS测试', '?', () => {
            this.testDNS()
          })
        }
      }
      .columnsTemplate('1fr 1fr')
      .rowsTemplate('1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .width('100%')
      .height(120)
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildNetworkSettingsCard() {
    Column({ space: 20 }) {
      Text('⚙️ 网络设置')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
        .alignSelf(ItemAlign.Start)

      Column({ space: 1 }) {
        this.buildSettingItem('自动重试', '网络失败时自动重试', true)
        this.buildSettingItem('缓存优先', '优先使用本地缓存', true)
        this.buildSettingItem('数据压缩', '启用请求数据压缩', false)
        this.buildSettingItem('HTTPS优先', '优先使用HTTPS协议', true)
      }
      .width('100%')
      .backgroundColor('#F8F9FA')
      .borderRadius(12)
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildHistoryPage() {
    Column({ space: 20 }) {
      Row() {
        Text('? 请求历史')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
          .layoutWeight(1)
        Text('清空')
          .fontSize(14)
          .fontColor('#667eea')
          .onClick(() => {
            this.requestHistory = []
          })
      }
      .width('100%')
      .padding({ left: 20, right: 20 })

      if (this.requestHistory.length === 0) {
        this.buildEmptyHistoryView()
      } else {
        List({ space: 10 }) {
          ForEach(this.requestHistory, (history: RequestHistory) => {
            ListItem() {
              this.buildHistoryItem(history)
            }
          })
        }
        .width('100%')
        .layoutWeight(1)
        .padding({ left: 20, right: 20 })
      }
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  buildCachePage() {
    Column({ space: 20 }) {
      Row() {
        Text('? 缓存管理')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
          .layoutWeight(1)
        Text('清空全部')
          .fontSize(14)
          .fontColor('#FF4444')
          .onClick(() => {
            this.clearAllCache()
          })
      }
      .width('100%')
      .padding({ left: 20, right: 20 })

      this.buildCacheStatsCard()

      if (this.cacheList.length === 0) {
        this.buildEmptyCacheView()
      } else {
        List({ space: 10 }) {
          ForEach(this.cacheList, (cache: CacheData) => {
            ListItem() {
              this.buildCacheItem(cache)
            }
          })
        }
        .width('100%')
        .layoutWeight(1)
        .padding({ left: 20, right: 20 })
      }
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  buildStatusItem(label: string, value: string, icon: string) {
    Row({ space: 15 }) {
      Text(icon)
        .fontSize(20)
        .width(30)
        .textAlign(TextAlign.Center)
      Text(label)
        .fontSize(16)
        .fontColor('#333333')
        .layoutWeight(1)
      Text(value)
        .fontSize(16)
        .fontColor('#666666')
        .fontWeight(FontWeight.Medium)
    }
    .width('100%')
    .height(50)
    .backgroundColor('#F8F9FA')
    .borderRadius(10)
    .padding({ left: 15, right: 15 })
  }

  @Builder
  buildTestButton(title: string, icon: string, onClick: () => void) {
    Column({ space: 8 }) {
      Text(icon)
        .fontSize(24)
      Text(title)
        .fontSize(12)
        .fontColor('#333333')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8F9FA')
    .borderRadius(10)
    .justifyContent(FlexAlign.Center)
    .onClick(onClick)
  }

  @Builder
  buildSettingItem(title: string, subtitle: string, enabled: boolean) {
    Row({ space: 15 }) {
      Column({ space: 5 }) {
        Text(title)
          .fontSize(16)
          .fontColor('#333333')
          .alignSelf(ItemAlign.Start)
        Text(subtitle)
          .fontSize(14)
          .fontColor('#666666')
          .alignSelf(ItemAlign.Start)
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      Toggle({ type: ToggleType.Switch, isOn: enabled })
        .selectedColor('#667eea')
        .onChange((isOn: boolean) => {
          console.log(`${title} switched to:`, isOn)
        })
    }
    .width('100%')
    .height(60)
    .padding({ left: 15, right: 15 })
    .backgroundColor(Color.White)
  }

  @Builder
  buildEmptyHistoryView() {
    Column({ space: 20 }) {
      Text('?')
        .fontSize(60)
      Text('暂无请求历史')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
      Text('开始搜索诗词后,这里将显示请求记录')
        .fontSize(14)
        .fontColor('#666666')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height(200)
    .justifyContent(FlexAlign.Center)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildHistoryItem(history: RequestHistory) {
    Row({ space: 15 }) {
      Text(history.success ? '✅' : '❌')
        .fontSize(20)
        .width(30)
        .textAlign(TextAlign.Center)
      Column({ space: 8 }) {
        Text(`关键词:${history.keyword}`)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
        Row({ space: 10 }) {
          Text(`响应时间:${history.responseTime}ms`)
            .fontSize(12)
            .fontColor('#666666')
          Text(`|`)
            .fontSize(12)
            .fontColor('#CCCCCC')
          Text(this.formatTime(history.timestamp))
            .fontSize(12)
            .fontColor('#666666')
        }
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      Text('?')
        .fontSize(16)
        .fontColor('#667eea')
        .onClick(() => {
          this.searchKeyword = history.keyword
          this.searchPoetry()
        })
    }
    .width('100%')
    .height(70)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .padding(15)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildCacheStatsCard() {
    Column({ space: 15 }) {
      Text('? 缓存统计')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
        .alignSelf(ItemAlign.Start)

      Row() {
        this.buildStatItem('缓存条目', this.cacheList.length.toString(), '?')
        this.buildStatItem('占用空间', this.calculateCacheSize(), '?')
        this.buildStatItem('命中率', '85%', '?')
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildStatItem(label: string, value: string, icon: string) {
    Column({ space: 8 }) {
      Text(icon)
        .fontSize(24)
      Text(value)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#667eea')
      Text(label)
        .fontSize(12)
        .fontColor('#666666')
    }
    .width(80)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  buildEmptyCacheView() {
    Column({ space: 20 }) {
      Text('?')
        .fontSize(60)
      Text('暂无缓存数据')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
      Text('搜索诗词后,数据将自动缓存到本地')
        .fontSize(14)
        .fontColor('#666666')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height(200)
    .justifyContent(FlexAlign.Center)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .padding(20)
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildCacheItem(cache: CacheData) {
    Row({ space: 15 }) {
      Text('?')
        .fontSize(20)
        .width(30)
        .textAlign(TextAlign.Center)
      Column({ space: 8 }) {
        Text(`关键词:${cache.key}`)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
        Row({ space: 10 }) {
          Text(`${cache.data.length}条数据`)
            .fontSize(12)
            .fontColor('#666666')
          Text(`|`)
            .fontSize(12)
            .fontColor('#CCCCCC')
          Text(this.isExpired(cache) ? '已过期' : '有效')
            .fontSize(12)
            .fontColor(this.isExpired(cache) ? '#FF4444' : '#27AE60')
        }
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      Text('?️')
        .fontSize(16)
        .fontColor('#FF4444')
        .onClick(() => {
          this.deleteCacheItem(cache.key)
        })
    }
    .width('100%')
    .height(70)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .padding(15)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  // 网络请求方法
  async searchPoetry() {
    if (!this.searchKeyword.trim()) {
      return
    }

    // 检查缓存
    const cachedData = this.getCachedData(this.searchKeyword)
    if (cachedData && !this.isExpired(cachedData)) {
      this.poetryList = cachedData.data
      this.errorMessage = ''
      return
    }

    this.isLoading = true
    this.errorMessage = ''
    this.poetryList = []

    const startTime = Date.now()

    try {
      const url = `${this.API_BASE_URL}?info=${encodeURIComponent(this.searchKeyword)}`

      const response = await this.httpRequest.request(url, {
        method: http.RequestMethod.GET,
        header: {
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        connectTimeout: 10000,
        readTimeout: 10000
      })

      const responseTime = Date.now() - startTime

      if (response.responseCode === 200) {
        const data = JSON.parse(response.result.toString()) as PoetryData[]
        this.poetryList = data

        // 缓存数据
        this.cacheData(this.searchKeyword, data)

        // 记录请求历史
        this.addRequestHistory(this.searchKeyword, true, responseTime)
      } else {
        throw new Error(`HTTP ${response.responseCode}: ${response.result}`)
      }
    } catch (error) {
      console.error('Search poetry failed:', error)
      this.errorMessage = this.getErrorMessage(error)

      // 记录失败的请求历史
      const responseTime = Date.now() - startTime
      this.addRequestHistory(this.searchKeyword, false, responseTime)
    } finally {
      this.isLoading = false
    }
  }

  // 网络状态监控
  initNetworkMonitoring() {
    try {
      connection.getDefaultNet().then((netHandle) => {
        connection.getConnectionProperties(netHandle).then((properties) => {
          this.updateNetworkStatus()
        })
      })

      // 简化网络状态监控,避免复杂的类型问题
      this.checkNetworkStatus()
    } catch (error) {
      console.error('Failed to initialize network monitoring:', error)
    }
  }

  checkNetworkStatus() {
    try {
      connection.hasDefaultNet().then((hasNet) => {
        this.networkStatus.isConnected = hasNet
        if (hasNet) {
          this.updateNetworkStatus()
        }
      })
    } catch (error) {
      console.error('Failed to check network status:', error)
      this.networkStatus.isConnected = false
    }
  }

  updateNetworkStatus() {
    this.networkStatus.isConnected = true
    this.networkStatus.networkType = 'WiFi' // 简化处理
    this.networkStatus.signalStrength = Math.floor(Math.random() * 30) + 70 // 模拟信号强度
  }

  // 网络测试方法
  async testConnectivity() {
    console.log('Testing connectivity...')
    // 实现连通性测试逻辑
  }

  async testSpeed() {
    console.log('Testing speed...')
    // 实现速度测试逻辑
  }

  async testLatency() {
    console.log('Testing latency...')
    // 实现延迟测试逻辑
  }

  async testDNS() {
    console.log('Testing DNS...')
    // 实现DNS测试逻辑
  }

  // 缓存管理方法
  getCachedData(key: string): CacheData | null {
    return this.cacheList.find(cache => cache.key === key) || null
  }

  cacheData(key: string, data: PoetryData[]) {
    const existingIndex = this.cacheList.findIndex(cache => cache.key === key)
    const cacheItem: CacheData = {
      key,
      data,
      timestamp: Date.now(),
      expireTime: Date.now() + this.CACHE_EXPIRE_TIME
    }

    if (existingIndex >= 0) {
      this.cacheList[existingIndex] = cacheItem
    } else {
      this.cacheList.push(cacheItem)
    }
  }

  isExpired(cache: CacheData): boolean {
    return Date.now() > cache.expireTime
  }

  deleteCacheItem(key: string) {
    const index = this.cacheList.findIndex(cache => cache.key === key)
    if (index >= 0) {
      this.cacheList.splice(index, 1)
    }
  }

  clearAllCache() {
    this.cacheList = []
  }

  calculateCacheSize(): string {
    const totalItems = this.cacheList.reduce((sum, cache) => sum + cache.data.length, 0)
    const estimatedSize = totalItems * 200 // 估算每条数据200字节
    if (estimatedSize < 1024) {
      return `${estimatedSize}B`
    } else if (estimatedSize < 1024 * 1024) {
      return `${Math.round(estimatedSize / 1024)}KB`
    } else {
      return `${Math.round(estimatedSize / (1024 * 1024))}MB`
    }
  }

  // 请求历史管理
  addRequestHistory(keyword: string, success: boolean, responseTime: number) {
    const historyItem: RequestHistory = {
      id: Date.now(),
      keyword,
      timestamp: Date.now(),
      success,
      responseTime
    }
    this.requestHistory.unshift(historyItem)

    // 限制历史记录数量
    if (this.requestHistory.length > 50) {
      this.requestHistory = this.requestHistory.slice(0, 50)
    }
  }

  loadRequestHistory() {
    // 从本地存储加载请求历史
    // 这里可以使用preferences或数据库
  }

  loadCacheData() {
    // 从本地存储加载缓存数据
    // 这里可以使用preferences或数据库
  }

  // 工具方法
  getErrorMessage(error: Error | BusinessError): string {

    if (error.message) {
      return error.message
    } else {
      return '网络请求失败,请稍后重试'
    }
  }

  formatTime(timestamp: number): string {
    const date = new Date(timestamp)
    const now = new Date()
    const diff = now.getTime() - timestamp

    if (diff < 60000) { // 1分钟内
      return '刚刚'
    } else if (diff < 3600000) { // 1小时内
      return `${Math.floor(diff / 60000)}分钟前`
    } else if (diff < 86400000) { // 1天内
      return `${Math.floor(diff / 3600000)}小时前`
    } else {
      return `${date.getMonth() + 1}月${date.getDate()}日`
    }
  }
}
⚙️ 配置文件
代码语言:javascript
复制
// module.json5 配置
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_permission_reason",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.GET_NETWORK_INFO",
        "reason": "$string:network_info_permission_reason",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
        }
      }
    ],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ts",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background"
      }
    ]
  }
}

? 运行效果

? 界面展示

运行后的界面将展示:

  • ? 现代化设计:渐变色标题栏和精美的卡片设计
  • ? 四个功能页面:诗词查询、网络状态、请求历史、缓存管理
  • ? 诗词查询页:搜索输入框 + 热门搜索 + 结果展示
  • ? 网络状态页:实时网络状态 + 网络测试 + 设置选项
  • ? 请求历史页:历史记录列表 + 重试功能
  • ? 缓存管理页:缓存统计 + 缓存列表 + 清理功能
✅ 功能验证
  1. 网络请求:输入关键词,观察请求发送和响应处理
  2. 加载状态:观察加载动画和状态提示
  3. 错误处理:断网或输入错误URL测试错误处理
  4. 缓存机制:重复搜索相同关键词验证缓存功能
  5. 网络监控:切换网络状态观察实时监控
  6. 历史记录:查看请求历史和重试功能

? 开发小贴士

? 最佳实践
  • ? 权限申请:确保在module.json5中申请网络相关权限
  • ? 用户体验:提供清晰的加载状态和错误提示
  • 性能优化:使用缓存机制减少不必要的网络请求
  • ? 错误处理:针对不同错误类型提供相应的处理策略
? 常见问题
  1. 网络权限:确保已申请INTERNET和GET_NETWORK_INFO权限
  2. 请求超时:设置合理的连接和读取超时时间
  3. JSON解析:处理服务器返回的非标准JSON格式
  4. 内存泄漏:及时销毁HttpRequest对象和取消监听
? 扩展学习
  • WebSocket:学习实时通信的WebSocket使用
  • 文件上传下载:实现文件传输功能
  • 网络安全:了解HTTPS和数据加密

? 总结与展望

通过这个Demo,我们学习了:

  • ✨ HarmonyOS网络请求的完整流程和最佳实践
  • ? 网络状态监控和连接管理的实现方法
  • ? 缓存机制和离线支持的开发技巧
  • ? 用户友好的网络应用界面设计

网络连接管理是现代移动应用的核心功能之一,掌握其各种用法对于创建稳定可靠的应用至关重要。从简单的HTTP请求到复杂的网络状态管理,每一个细节都体现着应用的专业性和用户体验。

这个示例展示了如何构建一个完整的网络应用,包含了实际项目中常见的功能需求。通过合理的架构设计和优化策略,我们能够创建出既稳定又高效的网络应用。

希望这个示例能够帮助到正在学习HarmonyOS开发的你!下一期我们将探索更多高级功能和开发技巧,敬请期待!如果你有任何问题或建议,欢迎在评论区留言交流。


? 相关资源


? 如果这篇文章对你有帮助,请点赞支持!?

让我们一起在HarmonyOS的世界里创造更多可能!


© 2025 红目香薰 | 用心分享,用技术创造价值

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ✨ 写在前面的话
  • ? Demo功能说明
    • ? 核心功能
    • ✨ 特色亮点
    • ? 界面展示
    • ? 适用场景
  • ? 核心代码说明
    • ? 项目结构
    • ? 关键技术点
      • 1. HTTP请求基础结构
      • 2. 网络状态监控
      • 3. 请求拦截和处理
      • 4. 错误处理机制
    • ? 技术要点解析
  • ? 完整Demo代码
    • ? 主页面代码
    • ⚙️ 配置文件
  • ? 运行效果
    • ? 界面展示
    • ✅ 功能验证
  • ? 开发小贴士
    • ? 最佳实践
    • ? 常见问题
    • ? 扩展学习
  • ? 总结与展望
  • ? 相关资源
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档