最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

flutter - Why does pushing images to cache first load them faster than retrieving from database directly? - Stack Overflow

programmeradmin5浏览0评论

I have a page with a ListView, each tile contains an image and text. The tiles are generated from a list of objects. Each object has properties text and imageId. imageId is used to retrieve the image from the "images" table in the local database. The "images" table has columns id (TEXT) and picture (BLOB). I am using SQLite with sqflite (mobile) and sqflite_common_ffi (desktop).

List<Request> _requests = [];
List<ImagesItem> _images = [];
bool _isLoading = true;

@override
void initState() {
  super.initState();
  loadRequests();
}

void loadRequests() async {
  try {
    var requests = await RequestsRepository().getAllRequests();
    requests = requests.take(1).toList(); // take(1) for testing purposes
    var alreadyStoredImages = _images.map((image) => image.id).toSet();
    var images = await ImageRepository().getImagesByIds(
      requests
          .map((request) => request.imageId)
          .where((imageId) => !alreadyStoredImages.contains(imageId))
          .toList(),
    );

    setState(() {
      _images = images;
      _requests = requests;
    });
  } catch (error) {
    // Handle error
  } finally {
    setState(() {
      _isLoading = false;
    });
  }
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: _isLoading
        ? const Center(child: CircularProgressIndicator())
        : ListView.builder(
            itemCount: _requests.length,
            itemBuilder: (context, index) {
              final request = _requests[index];
              final image = _images.firstWhere(
                (img) => img.id == request.imageId,
              );
              return ListTile(
                leading: Image.memory(
                  image.picture,
                  width: 50,
                  height: 50,
                ),
              );
            },
          ),
  );
}

The text appears instantly but the images take about 2 seconds to load. Is it normal for images to take this long to load from a local database? I could show a loader before showing the ListView but I don't know how to let the Image Widget load the image and after that show everything.

In another attempt with PrecacheImage the images are MemoryImage instead of Uint8List. The Image widget uses MemoryImage instead of Image.memory(). The page loads almost instantly. The code changed with precacheImage:

class _RequestWithImagePreCache {
  final String id;
  final MemoryImage image;

  _RequestWithImagePreCache(this.id, this.image);
}
List<_RequestWithImagePreCache> _images = [];

void loadRequests() async {
    try {
      var requests = await RequestsRepository().getAllRequests();
    requests = requests.take(1).toList(); // take(1) for testing purposes
      var alreadyStoredImages = _images.map((image) => image.id).toSet();
      var images = await ImageRepository().getImagesByIds(
        requests
            .map((request) => request.imageId)
            .where((imageId) => !alreadyStoredImages.contains(imageId))
            .toList(),
      );

      List<_RequestWithImagePreCache> imagesCached = [];
      await Future.wait(images.map((image) async {
        final memoryImage = MemoryImage(image.picture);
        await precacheImage(memoryImage, context);
        imagesCached.add(_RequestWithImagePreCache(image.id, memoryImage));
      }));

      setState(() {
        _images = imagesCached;
        _requests = requests;
      });
    } catch (error) {
      // Handle any errors during data fetching
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

The use of precacheImage is not clear to me as all guides use it in the context of images retrieved from the web, or use the package cached_network_image which I believe uses precacheImage or something similar. Is there a behavior to follow and why does the second case load faster even if I have to push images to cache instead of directly using them after retrieving from database?

I have a page with a ListView, each tile contains an image and text. The tiles are generated from a list of objects. Each object has properties text and imageId. imageId is used to retrieve the image from the "images" table in the local database. The "images" table has columns id (TEXT) and picture (BLOB). I am using SQLite with sqflite (mobile) and sqflite_common_ffi (desktop).

List<Request> _requests = [];
List<ImagesItem> _images = [];
bool _isLoading = true;

@override
void initState() {
  super.initState();
  loadRequests();
}

void loadRequests() async {
  try {
    var requests = await RequestsRepository().getAllRequests();
    requests = requests.take(1).toList(); // take(1) for testing purposes
    var alreadyStoredImages = _images.map((image) => image.id).toSet();
    var images = await ImageRepository().getImagesByIds(
      requests
          .map((request) => request.imageId)
          .where((imageId) => !alreadyStoredImages.contains(imageId))
          .toList(),
    );

    setState(() {
      _images = images;
      _requests = requests;
    });
  } catch (error) {
    // Handle error
  } finally {
    setState(() {
      _isLoading = false;
    });
  }
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: _isLoading
        ? const Center(child: CircularProgressIndicator())
        : ListView.builder(
            itemCount: _requests.length,
            itemBuilder: (context, index) {
              final request = _requests[index];
              final image = _images.firstWhere(
                (img) => img.id == request.imageId,
              );
              return ListTile(
                leading: Image.memory(
                  image.picture,
                  width: 50,
                  height: 50,
                ),
              );
            },
          ),
  );
}

The text appears instantly but the images take about 2 seconds to load. Is it normal for images to take this long to load from a local database? I could show a loader before showing the ListView but I don't know how to let the Image Widget load the image and after that show everything.

In another attempt with PrecacheImage the images are MemoryImage instead of Uint8List. The Image widget uses MemoryImage instead of Image.memory(). The page loads almost instantly. The code changed with precacheImage:

class _RequestWithImagePreCache {
  final String id;
  final MemoryImage image;

  _RequestWithImagePreCache(this.id, this.image);
}
List<_RequestWithImagePreCache> _images = [];

void loadRequests() async {
    try {
      var requests = await RequestsRepository().getAllRequests();
    requests = requests.take(1).toList(); // take(1) for testing purposes
      var alreadyStoredImages = _images.map((image) => image.id).toSet();
      var images = await ImageRepository().getImagesByIds(
        requests
            .map((request) => request.imageId)
            .where((imageId) => !alreadyStoredImages.contains(imageId))
            .toList(),
      );

      List<_RequestWithImagePreCache> imagesCached = [];
      await Future.wait(images.map((image) async {
        final memoryImage = MemoryImage(image.picture);
        await precacheImage(memoryImage, context);
        imagesCached.add(_RequestWithImagePreCache(image.id, memoryImage));
      }));

      setState(() {
        _images = imagesCached;
        _requests = requests;
      });
    } catch (error) {
      // Handle any errors during data fetching
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

The use of precacheImage is not clear to me as all guides use it in the context of images retrieved from the web, or use the package cached_network_image which I believe uses precacheImage or something similar. Is there a behavior to follow and why does the second case load faster even if I have to push images to cache instead of directly using them after retrieving from database?

Share Improve this question edited Nov 19, 2024 at 23:01 user4157124 2,99614 gold badges31 silver badges46 bronze badges asked Nov 19, 2024 at 8:25 Bug DepartmentBug Department 112 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

as I read precacheImage concept is like Cache image in CacheManager in theory it should slow on load image first time and store it in cache when reused the same image it will used cache instead of make a new one instant

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论