ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-fast-image — 高性能图片加载组件

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📌 开发环境声明:本文基于 React Native 0.72.90 版本进行开发适配


🚀 一、开篇引言

图片加载是最常见也是最影响性能的场景之一。React Native 内置的 Image 组件虽然能满足基本需求,但在处理大量图片、列表滚动等场景时往往表现不佳。react-native-fast-image 是一个高性能的图片加载组件,它封装了 iOS 的 SDWebImage 和 Android 的 Glide,提供了优秀的内存管理和缓存机制。本文将带你深入了解如何在 HarmonyOS 平台上集成和使用 react-native-fast-image,实现高效的图片加载体验。

1.1 你将学到什么?

  • ✅ react-native-fast-image 的核心概念与工作原理
  • ✅ HarmonyOS 平台的完整集成流程
  • ✅ 多种实战场景的代码实现(图片列表、头像组件、预加载优化)
  • ✅ 图片加载回调与错误处理
  • ✅ 缓存管理与性能优化

1.2 适用人群

  • 正在进行 React Native 鸿蒙化迁移的开发者
  • 需要优化图片加载性能的应用开发者
  • 对跨平台高性能组件开发感兴趣的技术爱好者

📦 二、库概览

2.1 基本信息

项目 内容
库名称 react-native-fast-image
维护方 DylanVann
最新版本 8.6.3 (RN 0.72)
RN 0.72 适配包 @react-native-oh-tpl/react-native-fast-image@8.6.3-0.4.17
官方仓库 https://github.com/DylanVann/react-native-fast-image
鸿蒙适配仓库 https://github.com/react-native-oh-library/react-native-fast-image
开源协议 MIT

2.2 核心能力矩阵

能力项 描述 HarmonyOS 支持
远程图片加载 支持网络 URL 加载 ✅ 完全支持
本地图片加载 支持本地资源加载 ✅ 完全支持
图片缓存 内存缓存和磁盘缓存 ✅ 完全支持
预加载 预加载图片到缓存 ✅ 完全支持
加载回调 开始、进度、完成、错误回调 ✅ 完全支持
优先级控制 加载优先级设置 ❌ 暂不支持
缓存策略 自定义缓存模式 ❌ 暂不支持
着色 图片颜色叠加 ✅ 完全支持

2.3 技术架构图

原生平台层
Bridge Layer
React Native 应用层
FastImage Component (JS/TS)
Props: source, resizeMode
Events: onLoad, onError
Methods: preload, clearCache
Native Module
FastImagePackage
FastImageViewManager
iOS

SDWebImage
Android

Glide
HarmonyOS

Image (ArkTS)

2.4 与同类方案对比

特性 react-native-fast-image React Native Image expo-image
HarmonyOS 支持 ⚠️ 需适配
内存缓存 ✅ 自动管理 ⚠️ 手动管理
磁盘缓存 ✅ 自动管理 ⚠️ 有限支持
预加载
加载进度
优先级控制
列表滚动性能 优秀 一般 优秀

⚡ 三、快速开始

3.1 环境要求

依赖项 版本要求
React Native 0.72.x
RNOH (鸿蒙框架) 0.72.90
HarmonyOS SDK 6.0.0.47+ (API 20)
DevEco Studio 5.0.3+ / 6.0+
Node.js 16.18.0+ / 18.x

3.2 版本说明

三方库版本 发布信息 支持RN版本
8.6.3-0.4.17 @react-native-oh-tpl/react-native-fast-image Releases 0.72

3.3 一键安装

创建鸿蒙项目的过程不在进行描述了,不懂得看这篇:https://blog.csdn.net/u011178696/article/details/151932277

bash 复制代码
# 安装鸿蒙适配包
npm install @react-native-oh-tpl/react-native-fast-image@8.6.3-0.4.17-rc.1

3.4 验证安装

bash 复制代码
# 检查 package.json
type package.json | findstr fast-image

# 预期输出
# "@react-native-oh-tpl/react-native-fast-image": "^8.6.3-0.4.17-rc.1"

🔧 四、HarmonyOS 集成详解

4.1 配置清单

📌 按顺序完成以下配置,缺一不可

步骤 配置文件 操作 重要程度
1 harmony/oh-package.json5 添加 overrides ⭐⭐⭐
2 harmony/entry/oh-package.json5 添加 har 依赖 ⭐⭐⭐
3 harmony/entry/src/main/cpp/CMakeLists.txt 配置编译链接 ⭐⭐⭐
4 harmony/entry/src/main/cpp/PackageProvider.cpp 引入头文件 ⭐⭐⭐
5 harmony/entry/src/main/ets/RNPackagesFactory.ts 引入 Package ⭐⭐⭐

💡 注意:react-native-fast-image 8.6.3-0.4.17 版本暂不支持 Autolink,需要手动配置原生依赖。

4.2 步骤详解(一定要根据自己的版本来)

步骤一:配置 overrides
json 复制代码
// 文件:harmony/oh-package.json5
{
  "name": "MyApplication",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {},
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}
步骤二:引入原生端代码

💡 提供两种引入方式,推荐使用 方法一(har 包引入)

方法一:通过 har 包引入(推荐)

📌 har 包位于三方库安装路径的 harmony 文件夹下

打开 harmony/entry/oh-package.json5,添加以下依赖:

json 复制代码
{
  "name": "entry",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90",
    "@react-native-oh-tpl/react-native-fast-image": "file:../../node_modules/@react-native-oh-tpl/react-native-fast-image/harmony/fast_image.har"
  }
}

点击 DevEco Studio 右上角的 Sync Now 按钮,或在终端执行:

bash 复制代码
cd harmony/entry
ohpm install
方法二:直接链接源码

📌 目前 DevEco Studio 不支持通过源码引入外部 module,需要将源码通过操作改成 harmony 工程的内部模块

步骤 1:复制源码到 harmony 工程根目录

<RN工程>/node_modules/@react-native-oh-tpl/react-native-fast-image/harmony/ 目录下的源码 fast_image 复制到 harmony 工程根目录下:

复制代码
harmony/
├── entry/
├── fast_image/          ← 复制过来的源码目录
└── build-profile.json5

步骤 2 :在 build-profile.json5 添加模块配置

打开 harmony/build-profile.json5,添加以下模块:

json 复制代码
{
  "app": {
    "signingConfigs": [],
    "products": [],
    "buildModeSet": []
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": []
    },
    {
      "name": "fast_image",
      "srcPath": "./fast_image"
    }
  ]
}

💡 如果存在 build-profile.template.json5 文件,也需要同步添加上述 modules 配置。

步骤 3:修改源码中的依赖版本

打开 harmony/fast_image/oh-package.json5,修改 @rnoh/react-native-openharmony 版本与项目一致:

json 复制代码
{
  "name": "fast_image",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

步骤 4 :在 entry/oh-package.json5 添加依赖

打开 harmony/entry/oh-package.json5,添加以下依赖:

json 复制代码
{
  "name": "entry",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90",
    "@react-native-oh-tpl/react-native-fast-image": "file:../fast_image"
  }
}

步骤 5:同步项目

点击 DevEco Studio 右上角的 Sync Now 按钮,或在终端执行:

bash 复制代码
cd harmony/entry
ohpm install
步骤三:配置 CMake 编译
c 复制代码
# 文件:harmony/entry/src/main/cpp/CMakeLists.txt

project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@react-native-oh-tpl/react-native-fast-image/src/main/cpp" ./fast-image)
# RNOH_END: manual_package_linking_1

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_fast_image)
# RNOH_END: manual_package_linking_2
步骤四:引入 Package(C++ 层)
cpp 复制代码
// 文件:harmony/entry/src/main/cpp/PackageProvider.cpp

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "SamplePackage.h"
+ #include "FastImagePackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        std::make_shared<SamplePackage>(ctx),
        + std::make_shared<FastImagePackage>(ctx),
    };
}
步骤五:引入 Package(ArkTS 层)
typescript 复制代码
// 文件:harmony/entry/src/main/ets/RNPackagesFactory.ts

+ import { FastImagePackage } from '@react-native-oh-tpl/react-native-fast-image/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SamplePackage(ctx),
    + new FastImagePackage(ctx)
  ];
}

4.3 同步与编译

bash 复制代码
# 进入 entry 目录
cd harmony/entry

# 执行依赖同步
ohpm install

# 返回项目根目录
cd ../..

在 DevEco Studio 中点击右上角的 Sync Now 按钮,等待同步完成后编译运行。

4.4 添加 harmony 运行环境

在项目中的 package.json 中添加运行命令,harmony 运行使用 npm run harmony 命令

json 复制代码
"scripts": {
  "android": "react-native run-android",
  "ios": "react-native run-ios",
  "lint": "eslint .",
  "start": "react-native start",
  "test": "jest",
  "harmony": "react-native bundle-harmony --dev"
},

💻 五、实战演练

场景一:基础图片加载

需求描述:实现一个基础的网络图片加载组件,支持加载状态显示和错误处理。

实现代码

javascript 复制代码
import React, { useState } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ActivityIndicator,
} from 'react-native';
import FastImage, {
  OnLoadEvent,
  OnProgressEvent,
} from 'react-native-fast-image';

interface ImageLoaderProps {
  uri: string;
  width?: number;
  height?: number;
  borderRadius?: number;
}

export default function ImageLoader({
  uri = "https://c-ssl.dtstatic.com/uploads/blog/202301/04/20230104230849_a9a24.thumb.400_0.jpeg",
  width = 200,
  height = 200,
  borderRadius = 8,
}: ImageLoaderProps) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [imageSize, setImageSize] = useState({ width: 0, height: 0 });

  const handleLoadStart = () => {
    setLoading(true);
    setError(false);
    console.log('图片开始加载');
  };

  const handleProgress = (event: OnProgressEvent) => {
    const { loaded, total } = event.nativeEvent;
    console.log(`加载进度: ${loaded}/${total}`);
  };

  const handleLoad = (event: OnLoadEvent) => {
    setLoading(false);
    const { width: w, height: h } = event.nativeEvent;
    setImageSize({ width: w, height: h });
    console.log(`图片加载完成: ${w}x${h}`);
  };

  const handleError = () => {
    setLoading(false);
    setError(true);
    console.log('图片加载失败');
  };

  const handleLoadEnd = () => {
    console.log('加载流程结束');
  };

  if (error) {
    return (
      <View style={[styles.errorContainer, { width, height, borderRadius }]}>
        <Text style={styles.errorText}>加载失败</Text>
      </View>
    );
  }

  return (
    <View style={[styles.container, { width, height, borderRadius }]}>
      <FastImage
        style={styles.image}
        source={{ uri }}
        resizeMode={FastImage.resizeMode.contain}
        onLoadStart={handleLoadStart}
        onProgress={handleProgress}
        onLoad={handleLoad}
        onError={handleError}
        onLoadEnd={handleLoadEnd}
      />
      {loading && (
        <View style={styles.loadingOverlay}>
          <ActivityIndicator size="large" color="#4c669f" />
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    overflow: 'hidden',
    backgroundColor: '#f0f0f0',
  },
  image: {
    width: '100%',
    height: '100%',
  },
  loadingOverlay: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(255,255,255,0.8)',
  },
  errorContainer: {
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f5f5f5',
    borderWidth: 1,
    borderColor: '#ddd',
  },
  errorText: {
    fontSize: 14,
    color: '#999',
  },
});

使用示例

javascript 复制代码
import ImageLoader from './ImageLoader';

function App() {
  return (
    <View style={styles.container}>
      <ImageLoader
        uri="https://res8.vmallres.com/pimages/uomcdn/CN/pms/202205/gbom/6941487259298/428_428_D7BFF22D4678EB68440F914B352214C4mp_tds.png"
        width={300}
        height={300}
      />
    </View>
  );
}

场景二:图片列表优化

需求描述:实现一个高性能的图片列表,利用 FastImage 的缓存机制优化滚动性能。

实现代码

javascript 复制代码
import React, { useCallback, useMemo } from 'react';
import {
  View,
  Text,
  StyleSheet,
  FlatList,
  TouchableOpacity,
} from 'react-native';
import FastImage from 'react-native-fast-image';

interface ImageItem {
  id: string;
  uri: string;
  title: string;
}

interface ImageGridProps {
  images: ImageItem[];
  onImagePress?: (item: ImageItem) => void;
  columns?: number;
}

export default function ImageGrid({
  images,
  onImagePress,
  columns = 2,
}: ImageGridProps) {
  const renderItem = useCallback(
    ({ item, index }: { item: ImageItem; index: number }) => {
      return (
        <TouchableOpacity
          style={styles.itemContainer}
          onPress={() => onImagePress?.(item)}
          activeOpacity={0.8}
        >
          <FastImage
            style={styles.image}
            source={{ uri: item.uri }}
            resizeMode={FastImage.resizeMode.cover}
          />
          <View style={styles.titleOverlay}>
            <Text style={styles.title} numberOfLines={1}>
              {item.title}
            </Text>
          </View>
        </TouchableOpacity>
      );
    },
    [onImagePress]
  );

  const keyExtractor = useCallback(
    (item: ImageItem) => item.id,
    []
  );

  const getItemLayout = useCallback(
    (_: any, index: number) => ({
      length: 200,
      offset: 200 * Math.floor(index / columns),
      index,
    }),
    [columns]
  );

  return (
    <FlatList
      data={images}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      numColumns={columns}
      getItemLayout={getItemLayout}
      showsVerticalScrollIndicator={false}
      contentContainerStyle={styles.listContainer}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={5}
      removeClippedSubviews={true}
    />
  );
}

const styles = StyleSheet.create({
  listContainer: {
    padding: 8,
  },
  itemContainer: {
    flex: 1,
    margin: 4,
    height: 200,
    borderRadius: 12,
    overflow: 'hidden',
    backgroundColor: '#f0f0f0',
  },
  image: {
    width: '100%',
    height: '100%',
  },
  titleOverlay: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: 'rgba(0,0,0,0.6)',
    paddingVertical: 8,
    paddingHorizontal: 12,
  },
  title: {
    fontSize: 14,
    fontWeight: '500',
    color: '#FFFFFF',
  },
});

使用示例

javascript 复制代码
// 补全所有缺失的引入
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import ImageGrid from './ImageGrid';

// 示例数据
const SAMPLE_IMAGES = [
  {
    id: '1',
    uri: 'https://picsum.photos/400/400?random=1',
    title: '风景照片',
  },
  {
    id: '2',
    uri: 'https://picsum.photos/400/400?random=2',
    title: '城市夜景',
  },
  {
    id: '3',
    uri: 'https://picsum.photos/400/400?random=3',
    title: '自然风光',
  },
  {
    id: '4',
    uri: 'https://picsum.photos/400/400?random=4',
    title: '建筑摄影',
  },
];

// 补全样式
function GalleryScreen() {
  const handleImagePress = (item: { id: string; uri: string; title: string }) => {
    console.log('点击图片:', item.title);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.header}>图片画廊</Text>
      <ImageGrid
        images={SAMPLE_IMAGES}
        onImagePress={handleImagePress}
        columns={2}
      />
    </View>
  );
}

// 缺失的样式
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  header: {
    fontSize: 20,
    fontWeight: 'bold',
    padding: 16,
  },
});

export default GalleryScreen;

场景三:头像组件

需求描述:实现一个支持多种尺寸和样式的头像组件,支持默认头像和加载状态。

实现代码

javascript 复制代码
import React, { useState } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
} from 'react-native';
import FastImage from 'react-native-fast-image';

type AvatarSize = 'small' | 'medium' | 'large' | 'xlarge';

interface AvatarProps {
  uri?: string;
  name?: string;
  size?: AvatarSize;
  borderRadius?: number;
  onPress?: () => void;
  showBorder?: boolean;
  borderColor?: string;
}

const SIZE_MAP: Record<AvatarSize, number> = {
  small: 32,
  medium: 48,
  large: 64,
  xlarge: 96,
};

const FONT_SIZE_MAP: Record<AvatarSize, number> = {
  small: 12,
  medium: 16,
  large: 20,
  xlarge: 32,
};

export default function Avatar({
  uri,
  name,
  size = 'medium',
  borderRadius,
  onPress,
  showBorder = false,
  borderColor = '#4c669f',
}: AvatarProps) {
  const [error, setError] = useState(false);
  const avatarSize = SIZE_MAP[size];
  const fontSize = FONT_SIZE_MAP[size];
  const actualBorderRadius = borderRadius ?? avatarSize / 2;

  const getInitials = (name: string): string => {
    const parts = name.trim().split(' ');
    if (parts.length >= 2) {
      return (parts[0][0] + parts[1][0]).toUpperCase();
    }
    return name.slice(0, 2).toUpperCase();
  };

  const renderPlaceholder = () => (
    <View
      style={[
        styles.placeholder,
        {
          width: avatarSize,
          height: avatarSize,
          borderRadius: actualBorderRadius,
        },
      ]}
    >
      <Text style={[styles.initials, { fontSize }]}>
        {name ? getInitials(name) : '?'}
      </Text>
    </View>
  );

  const content = (
    <View
      style={[
        styles.container,
        {
          width: avatarSize,
          height: avatarSize,
          borderRadius: actualBorderRadius,
        },
        showBorder && {
          borderWidth: 2,
          borderColor,
        },
      ]}
    >
      {uri && !error ? (
        <FastImage
          style={styles.image}
          source={{ uri }}
          resizeMode={FastImage.resizeMode.cover}
          onError={() => setError(true)}
        />
      ) : (
        renderPlaceholder()
      )}
    </View>
  );

  if (onPress) {
    return (
      <TouchableOpacity onPress={onPress} activeOpacity={0.8}>
        {content}
      </TouchableOpacity>
    );
  }

  return content;
}

const styles = StyleSheet.create({
  container: {
    overflow: 'hidden',
    backgroundColor: '#e0e0e0',
  },
  image: {
    width: '100%',
    height: '100%',
  },
  placeholder: {
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#4c669f',
  },
  initials: {
    fontWeight: '600',
    color: '#FFFFFF',
  },
});

使用示例

javascript 复制代码
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import Avatar from './Avatar';

function UserList() {
  const users = [
    { id: '1', name: '张三', avatar: 'https://i.pravatar.cc/150?img=1' },
    { id: '2', name: '李四', avatar: 'https://i.pravatar.cc/150?img=2' },
    { id: '3', name: '王五', avatar: '' },
    { id: '4', name: '赵六', avatar: 'https://i.pravatar.cc/150?img=4' },
  ];

  return (
    <View style={styles.container}>
      {users.map((user) => (
        <View key={user.id} style={styles.userItem}>
          <Avatar
            uri={user.avatar}
            name={user.name}
            size="large"
            showBorder
            onPress={() => console.log('点击用户:', user.name)}
          />
          <Text style={styles.userName}>{user.name}</Text>
        </View>
      ))}
    </View>
  );
}

// 补全缺失的样式
const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
    backgroundColor: '#fff',
  },
  userItem: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 16,
    gap: 12,
  },
  userName: {
    fontSize: 16,
    color: '#333',
  },
});

export default UserList;

场景四:图片预加载与缓存管理

需求描述:实现图片预加载功能,提升用户体验,并提供缓存清理能力。

实现代码

javascript 复制代码
import React, { useEffect, useState } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
  Alert,
} from 'react-native';
import FastImage from 'react-native-fast-image';

interface CacheManagerProps {
  preloadImages?: string[];
}

export default function CacheManager({ preloadImages = [] }: CacheManagerProps) {
  const [preloadStatus, setPreloadStatus] = useState<'idle' | 'loading' | 'done'>('idle');

  useEffect(() => {
    if (preloadImages.length > 0) {
      handlePreload();
    }
  }, []);

  const handlePreload = async () => {
    if (preloadImages.length === 0) {
      Alert.alert('提示', '没有需要预加载的图片');
      return;
    }

    setPreloadStatus('loading');
  
    try {
      const sources = preloadImages.map((uri) => ({ uri }));
      await FastImage.preload(sources);
      setPreloadStatus('done');
      Alert.alert('成功', `已预加载 ${preloadImages.length} 张图片`);
    } catch (error) {
      setPreloadStatus('idle');
      Alert.alert('错误', '预加载失败');
    }
  };

  const handleClearMemoryCache = async () => {
    try {
      await FastImage.clearMemoryCache();
      Alert.alert('成功', '内存缓存已清理');
    } catch (error) {
      Alert.alert('错误', '清理内存缓存失败');
    }
  };

  const handleClearDiskCache = async () => {
    try {
      await FastImage.clearDiskCache();
      Alert.alert('成功', '磁盘缓存已清理');
    } catch (error) {
      Alert.alert('错误', '清理磁盘缓存失败');
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>缓存管理</Text>
  
      <View style={styles.statusContainer}>
        <Text style={styles.statusText}>
          预加载状态: {
            preloadStatus === 'idle' ? '未开始' :
            preloadStatus === 'loading' ? '加载中...' : '已完成'
          }
        </Text>
      </View>

      <TouchableOpacity style={styles.button} onPress={handlePreload}>
        <Text style={styles.buttonText}>预加载图片</Text>
      </TouchableOpacity>

      <TouchableOpacity
        style={[styles.button, styles.clearButton]}
        onPress={handleClearMemoryCache}
      >
        <Text style={styles.buttonText}>清理内存缓存</Text>
      </TouchableOpacity>

      <TouchableOpacity
        style={[styles.button, styles.clearButton]}
        onPress={handleClearDiskCache}
      >
        <Text style={styles.buttonText}>清理磁盘缓存</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#fff',
    borderRadius: 12,
    margin: 16,
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 16,
    color: '#333',
  },
  statusContainer: {
    padding: 12,
    backgroundColor: '#f5f5f5',
    borderRadius: 8,
    marginBottom: 16,
  },
  statusText: {
    fontSize: 14,
    color: '#666',
  },
  button: {
    backgroundColor: '#4c669f',
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    marginBottom: 12,
    alignItems: 'center',
  },
  clearButton: {
    backgroundColor: '#e74c3c',
  },
  buttonText: {
    fontSize: 16,
    fontWeight: '600',
    color: '#FFFFFF',
  },
});

📋 六、API 详解

6.1 Props 属性

属性名 描述 类型 必填 HarmonyOS 支持
source.uri 远程图片地址 string
source.headers 请求头信息,如 { Authorization: 'token' } object
source.priority 加载优先级 enum
source.cache 缓存模式 enum
defaultSource 默认图片(本地资源) number
resizeMode 缩放模式 enum
onLoadStart 图片开始加载时触发 function
onProgress 图片加载过程中触发,返回加载进度 function
onLoad 图片加载成功时触发,返回图片宽高 function
onError 图片加载失败时触发 function
onLoadEnd 图片加载结束时触发(无论成功或失败) function
tintColor 图片着色,将非透明像素替换为指定颜色 string| number

6.2 resizeMode 枚举值

描述
contain 保持宽高比缩放,完整显示在容器内
cover 保持宽高比缩放,填满容器
stretch 拉伸图片填满容器,不保持宽高比
center 居中显示,不缩放

6.3 静态方法

方法名 描述 参数 HarmonyOS 支持
FastImage.preload 预加载图片到缓存 sources: { uri: string }[]
FastImage.clearMemoryCache 清理内存缓存
FastImage.clearDiskCache 清理磁盘缓存

6.4 事件对象类型

typescript 复制代码
// 加载进度事件
interface OnProgressEvent {
  nativeEvent: {
    loaded: number;  // 已加载字节数
    total: number;   // 总字节数
  };
}

// 加载完成事件
interface OnLoadEvent {
  nativeEvent: {
    width: number;   // 图片宽度
    height: number;  // 图片高度
  };
}

⚠️ 七、常见问题与解决方案

7.1 图片不显示

问题描述:图片加载后不显示,或显示空白。

可能原因与解决方案

  1. URL 格式问题

    javascript 复制代码
    // ❌ 错误:URL 缺少协议
    source={{ uri: 'example.com/image.png' }}
    
    // ✅ 正确:完整的 URL
    source={{ uri: 'https://example.com/image.png' }}
  2. 样式问题

    javascript 复制代码
    // ❌ 错误:未设置尺寸
    <FastImage source={{ uri }} />
    
    // ✅ 正确:设置明确的尺寸
    <FastImage style={{ width: 200, height: 200 }} source={{ uri }} />
  3. HTTPS 证书问题(Android)

    • 在 AndroidManifest.xml 中添加 android:usesCleartextTraffic="true"

7.2 图片加载缓慢

问题描述:首次加载图片时速度较慢。

解决方案

  1. 使用预加载

    javascript 复制代码
    // 在应用启动时预加载常用图片
    FastImage.preload([
      { uri: 'https://example.com/avatar_default.png' },
      { uri: 'https://example.com/logo.png' },
    ]);
  2. 使用缩略图

    javascript 复制代码
    // 先加载小图,再加载大图
    <FastImage
      source={{ uri: thumbnailUrl }}
      onLoad={() => {
        // 加载完成后可以预加载高清图
        FastImage.preload([{ uri: highResUrl }]);
      }}
    />

7.3 内存占用过高

问题描述:应用内存占用持续增长。

解决方案

javascript 复制代码
// 在合适的时机清理缓存
useEffect(() => {
  return () => {
    // 组件卸载时清理内存缓存
    FastImage.clearMemoryCache();
  };
}, []);

// 用户手动清理
const handleClearCache = async () => {
  await FastImage.clearMemoryCache();
  await FastImage.clearDiskCache();
};

7.4 HarmonyOS 特有问题

问题描述:部分属性在 HarmonyOS 上不支持。

解决方案

不支持属性 替代方案
source.priority 暂无替代方案,默认按加载顺序处理
source.cache 暂无替代方案,使用默认缓存策略

📊 八、最佳实践

8.1 性能优化建议

  1. 合理设置图片尺寸

    javascript 复制代码
    // 根据容器大小选择合适的图片尺寸
    const getImageUrl = (baseUrl: string, size: number) => {
      return `${baseUrl}?w=${size}&h=${size}`;
    };
  2. 列表优化配置

    javascript 复制代码
    <FlatList
      data={images}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={5}
      removeClippedSubviews={true}
      getItemLayout={getItemLayout}
    />
  3. 使用 React.memo 避免重复渲染

    javascript 复制代码
    const ImageItem = React.memo(({ uri, title }) => (
      <FastImage source={{ uri }} style={styles.image} />
    ));

8.2 错误处理规范

javascript 复制代码
const ImageWithErrorHandling = ({ uri }) => {
  const [error, setError] = useState(false);
  const [retryCount, setRetryCount] = useState(0);

  const handleError = () => {
    if (retryCount < 3) {
      setRetryCount(retryCount + 1);
    } else {
      setError(true);
    }
  };

  if (error) {
    return <DefaultImage />;
  }

  return (
    <FastImage
      key={`retry-${retryCount}`}
      source={{ uri }}
      onError={handleError}
    />
  );
};

8.3 TypeScript 类型定义

typescript 复制代码
import FastImage, {
  ResizeMode,
  OnLoadEvent,
  OnProgressEvent,
  Source,
} from 'react-native-fast-image';

interface CustomImageProps {
  source: Source | number;
  style?: StyleProp<ImageStyle>;
  resizeMode?: ResizeMode;
  onLoad?: (event: OnLoadEvent) => void;
  onError?: () => void;
}

🔗 九、参考资料


相关推荐
互联网散修2 小时前
零基础鸿蒙应用开发第六节:复杂数据类型入门 —— 数组、元组与枚举
华为·log4j·harmonyos
秋秋小事2 小时前
鸿蒙DevEvo Studio运行React Native生成的bundle文件遇到的一个问题
react native·react.js·鸿蒙
new code Boy2 小时前
Vue3转React速查表
前端·javascript·react.js
国医中兴2 小时前
Flutter 三方库 cloudflare_r2_uploader 的鸿蒙化适配指南 - 云端存储的疾速通道、在鸿蒙端实现 R2 分段上传实战
flutter·harmonyos·鸿蒙·openharmony·cloudflare_r2_uploader
盐焗西兰花3 小时前
鸿蒙学习实战之路-Share Kit系列(13/17)-配置目标应用名单(企业应用)
学习·华为·harmonyos
早點睡3903 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-linear-gradient-text
javascript·react native·react.js
Easonmax3 小时前
ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-image-picker — 图片选择器
react native·react.js·harmonyos
国医中兴3 小时前
Flutter 三方库 weaver 的鸿蒙化适配指南 - 玩转轻量级服务发现、在鸿蒙端实现模块化治理与解构实战
flutter·harmonyos·鸿蒙·openharmony
早點睡3903 小时前
ReactNative项目OpenHarmony三方库集成实战:@react-native-oh-tpl/react-native-fast-image
javascript·react native·react.js