You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter选择图片后页面不刷新,无法实时更新问题求助

问题描述

我希望App启动时随机显示一张asset图片(命名为image1至image6),通过生成1-6的随机数加载对应图片,同时允许用户在设置页将这6张默认图片替换为自定义图片。

我用Flutter实现了功能:用ImagePicker选择图片,复制到应用目录并命名为giris[ID].jpeg,路径存入sqflite数据库。但现在遇到问题:用户能正常替换默认图片,但无法在不退出页面的情况下替换已自定义的图片,只有退出并重新进入页面时图片才会更新,且没有报错信息。

现有代码

import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:persentilizlem/util/database_helper.dart';
import 'package:persentilizlem/util/girisresimmodel.dart';
import 'package:persentilizlem/util/imagepick_test.dart';
import 'package:persentilizlem/util/widgets/progressindicator.dart';

class PickImageSet extends StatefulWidget {
 const  PickImageSet( {Key? key}) : super(key: key);

  @override
  State<PickImageSet> createState() => _PickImageSetState();

}

class _PickImageSetState extends State<PickImageSet> {
  late DatabaseHelper _databaseHelper;
  File? image;
  final singleImagePick = ImagePicker();
  ImageCache _imageCache =  MyImageCache();
  

  @override
  void initState() {
    _databaseHelper = DatabaseHelper();
    super.initState();
  }
/////// Show image in screen
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        height: double.maxFinite,
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              FutureBuilder(
                  future: _databaseHelper.girisResimListesi(),
                  builder: (context, AsyncSnapshot<List<GirisResim>> snapshot) {
                    if (snapshot.hasData) {
                      return Expanded(
                          child: GridView.builder(
                              shrinkWrap: true,
                              itemCount: snapshot.data!.length,
                              gridDelegate:
                                  const SliverGridDelegateWithFixedCrossAxisCount(
                                      crossAxisCount: 2),
                              itemBuilder: (context, index) {
                                return Container(
                                  padding: const EdgeInsets.all(10),
                                  margin: const EdgeInsets.all(5),
                                  decoration: containerBoxDecoration(),
                                  child: snapshot.connectionState ==
                                          ConnectionState.active
                                      ? Icon(
                                          Icons.camera_alt_outlined,
                                          color: Colors.black.withOpacity(0.3),
                                        )
                                      : InkWell(
                                          onTap: () async {
                                            ImageSource? source =
                                                await pickImageSource(context);
                                            (source != null)
                                                ? pickImage(source,
                                                    snapshot.data![index].id)
                                                : null;
                                            _imageCache;
                                            setState(() {});

                                          },
                                          child: Stack(
                                            alignment:
                                                AlignmentDirectional.topStart,
                                            children: [
                                              snapshot.data![index].isAsset == 0
                                                  ? Image.asset(
                                                      snapshot.data![index]
                                                          .resimYol,
                                                      fit: BoxFit.fitHeight,
                                                    )
                                                  : Image.file(
                                                      File(snapshot.data![index]
                                                          .resimYol),
                                                      fit: BoxFit.fitHeight,
                                                    ),
                                              Icon(
                                                Icons.camera_alt_outlined,
                                                color: Colors.black
                                                    .withOpacity(0.3),
                                              ),
                                            ],
                                          ),
                                        ),
                                );
                              }));
                    } else {
                      return const ProgressBar();
                    }
                  }),
              const Text(
                  "Giriş kısmında görünen resimleri istediğiniz 6 resim ile değiştirebilirsiniz")
            ],
          ),
        ),
      ),
    );
  }

  ///// for image container decoration
  BoxDecoration containerBoxDecoration() {
    return BoxDecoration(
        color: Colors.white,
        border: Border.all(style: BorderStyle.solid, width: 0.3),
        borderRadius: BorderRadius.circular(10),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.5),
            spreadRadius: 5,
            blurRadius: 7,
            offset: const Offset(0, 3),
          )
        ]);
  }

  ///// pick image from source (camera or gallery)
  Future<ImageSource?> pickImageSource(BuildContext context) async {
    if (Platform.isIOS) {
      return showCupertinoModalPopup(
        context: context,
        builder: (context) => CupertinoActionSheet(
          title: const Text("İmage Kaynağı"),
          actions: [
            CupertinoActionSheetAction(
                onPressed: () => Navigator.of(context).pop(ImageSource.camera),
                child: const Text("Kamera")),
            CupertinoActionSheetAction(
                onPressed: () => Navigator.of(context).pop(ImageSource.gallery),
                child: const Text("Galeri")),
          ],
        ),
      );
    } else {
      return showModalBottomSheet(
          context: context,
          builder: (context) => Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  ListTile(
                      leading: const Icon(Icons.camera_alt),
                      title: const Text("Kamera"),
                      onTap: () =>
                          Navigator.of(context).pop(ImageSource.camera)),
                  ListTile(
                      leading: const Icon(Icons.image),
                      title: const Text("Galeri"),
                      onTap: () =>
                          Navigator.of(context).pop(ImageSource.gallery)),
                ],
              ));
    }
  }


    ///// for take image from source copy file app directory and write database
  Future<void> pickImage(ImageSource source, int? id) async {
    try {
      File image =  File((await ImagePicker().pickImage(source: source,maxWidth: 250))!.path);
      if (image == null) return null;
      final directory = await getApplicationDocumentsDirectory();
     final filebuster = await image.copy("${directory.path}/giris$id.jpeg");
      GirisResim resimdata =
      GirisResim(id: id!, resimYol: filebuster.path, isAsset: 1);
      _databaseHelper.girisResimGuncelle(resimdata);

      setState(() {
       this.image = File(resimdata.resimYol);
      });
    } on PlatformException catch (e) {
      print(e);
    }
  }
/*
//// I try empty cache
  Future<void> _deleteCacheDir() async {
    final cacheDir = await getTemporaryDirectory();

    if (cacheDir.existsSync()) {
      cacheDir.deleteSync(recursive: true);
    }
  }

  Future<void> _deleteAppDir() async {
    final appDir = await getApplicationSupportDirectory();

    if(appDir.existsSync()){
      appDir.deleteSync(recursive: true);
    }
  }
*/

}
问题原因&解决方案

核心问题

  1. FutureBuilder缓存数据:初始只执行一次数据库查询,后续数据库更新后不会自动重新拉取数据
  2. Flutter图片缓存:覆盖同路径图片后,Image组件会优先使用缓存中的旧图片,不会读取新文件内容

具体修复步骤

1. 让FutureBuilder重新获取数据

用状态变量控制Future的执行,触发刷新:

// 在State类中新增变量
late Future<List<GirisResim>> _imageListFuture;

@override
void initState() {
  super.initState();
  _databaseHelper = DatabaseHelper();
  _imageListFuture = _databaseHelper.girisResimListesi();
}

// 新增刷新方法
void _refreshImageList() {
  setState(() {
    _imageListFuture = _databaseHelper.girisResimListesi();
  });
}

然后将FutureBuilder的future参数替换为_imageListFuture。

2. 清除对应图片的缓存

在更新图片后,手动清除该路径图片的缓存:

// 在pickImage方法中,数据库更新后添加
final imageKey = FileImage(File(resimdata.resimYol)).key;
PaintingBinding.instance.imageCache.evict(imageKey);

3. 优化刷新逻辑

去掉无效的setState(() {}),调用_refreshImageList()触发UI更新,同时确保异步操作完成后再刷新:

// 修改pickImage方法的末尾
await _databaseHelper.girisResimGuncelle(resimdata);
// 清除缓存
final imageKey = FileImage(File(resimdata.resimYol)).key;
PaintingBinding.instance.imageCache.evict(imageKey);
// 刷新列表
_refreshImageList();

// 修改InkWell的onTap逻辑
onTap: () async {
  ImageSource? source = await pickImageSource(context);
  if (source != null) {
    await pickImage(source, snapshot.data![index].id);
  }
},

完整修改后的关键代码片段

class _PickImageSetState extends State<PickImageSet> {
  late DatabaseHelper _databaseHelper;
  late Future<List<GirisResim>> _imageListFuture;
  final singleImagePick = ImagePicker();

  @override
  void initState() {
    _databaseHelper = DatabaseHelper();
    _imageListFuture = _databaseHelper.girisResimListesi();
    super.initState();
  }

  void _refreshImageList() {
    setState(() {
      _imageListFuture = _databaseHelper.girisResimListesi();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        height: double.maxFinite,
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              FutureBuilder(
                  future: _imageListFuture,
                  builder: (context, AsyncSnapshot<List<GirisResim>> snapshot) {
                    // 原有UI代码不变
                  }),
              const Text("Giriş kısmında görünen resimleri istediğiniz 6 resim ile değiştirebilirsiniz")
            ],
          ),
        ),
      ),
    );
  }

  Future<void> pickImage(ImageSource source, int? id) async {
    try {
      final pickedFile = await ImagePicker().pickImage(source: source, maxWidth: 250);
      if (pickedFile == null) return;
      File image = File(pickedFile.path);
      final directory = await getApplicationDocumentsDirectory();
      final filebuster = await image.copy("${directory.path}/giris$id.jpeg");
      GirisResim resimdata = GirisResim(id: id!, resimYol: filebuster.path, isAsset: 1);
      
      await _databaseHelper.girisResimGuncelle(resimdata);
      
      // 清除缓存
      final imageKey = FileImage(File(resimdata.resimYol)).key;
      PaintingBinding.instance.imageCache.evict(imageKey);
      
      // 刷新列表
      _refreshImageList();
      
    } on PlatformException catch (e) {
      print(e);
    }
  }

  // 其他原有方法不变
}

内容的提问来源于stack exchange,提问作者GLSVR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:45:36