Mobile Development 9 min read

Optimizing Image Rendering in Flutter for E‑commerce Apps: FXTexImage V1‑V3

The article describes how Xianyu’s FXTexImage library (versions 1‑3) transforms product‑detail images in Flutter e‑commerce apps into native‑provided external textures, progressively reducing memory growth, eliminating duplicate downloads, and cutting CPU load via GPU‑thread cleanup and shared‑context texture reuse, boosting page push limits from ten to over thirty, lowering crash rates, and shrinking the app package by more than 900 KB.

Xianyu Technology
Xianyu Technology
Xianyu Technology
Optimizing Image Rendering in Flutter for E‑commerce Apps: FXTexImage V1‑V3

Background: In e‑commerce apps the product‑detail page is image‑heavy, often consuming more than 50% of page memory and causing frequent app crashes. Xianyu chose this page as the first Flutter migration target and encountered several issues:

1. Memory growth when repeatedly pushing detail pages. 2. Duplicate resources increasing the installation package. 3. Legacy address‑cache strategy could not be reused. 4. Native and Flutter downloaded the same images.

Solution – FXTexImage V1 : Treat each image as a static video and render it via an external_texture supplied by the native side. The native layer provides the texture data, while Flutter only displays the texture, allowing reuse of the existing native image library for download, cache and cropping.

Although V1 solved package size, cache and duplication, the memory problem remained.

Memory Optimization – FXTexImage V2 : Only keep image resources for the current page and its immediate predecessor; release earlier pages. Pre‑load the next page’s images during pop to keep the user experience seamless. The release of SurfaceTexture was moved from the main thread to the GPU thread’s destructor, adding glDeleteTextures calls. Sample destructor implementation:

AndroidExternalTextureGL::~AndroidExternalTextureGL(){
    if(state_ == AttachmentState::attached){
        Detach();
        if(texture_name_ != 0){
            glDeleteTextures(1, &texture_name_);
            texture_name_ = 0;
        }
    }
    state_ = AttachmentState::detached;
}

void AndroidExternalTextureGL::Release(){
    JNIEnv* env = fml::jni::AttachCurrentThread();
    auto surfaceTexture = surface_texture_.get(env);
    if(!surfaceTexture.is_null()){
        SurfaceTextureRelease(env, surfaceTexture.obj());
    }
}

void SurfaceTextureRelease(JNIEnv* env, jobject obj){
    env->CallVoidMethod(obj, g_release_method);
    FML_CHECK(CheckException(env));
}

V2 reduced the memory growth rate, allowing up to 30+ detail pages to be pushed on iPhone 6P (versus ~10 before).

CPU Optimization – FXTexImage V3 : Adopt a shared‑context external‑texture approach (originally used for video) so that each image is converted to an OpenGL texture once and then reused, eliminating repeated CPU‑intensive pixel‑buffer‑to‑texture conversions on both iOS and Android. This cut CPU usage to only ~3% higher than the native Flutter image widget while keeping memory stable.

Results: • Push limit increased from 10 to >30 pages. • Abort rate dropped by 20%. • Installation package reduced by >900 KB (all new resources removed except GIFs). • Native image download/cache logic reused, preserving existing address strategies.

Remaining issues: occasional high CPU due to frequent native‑Flutter channel calls for many images, and aliasing when scaling small native images to textures. Further work includes batch channel operations and anti‑aliasing research. The component is still being refined and will be open‑sourced on GitHub.

FlutterMobile Developmentperformance optimizationexternal-texturememory managementImage Rendering
Xianyu Technology
Written by

Xianyu Technology

Official account of the Xianyu technology team

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.