【问题标题】:flutter Infinite Scroll View with MySQL用 MySQL 扑动无限滚动视图
【发布时间】:2019-01-30 00:19:13
【问题描述】:

最近我在一个类似画廊的项目上工作,该项目显示了来自数据库的一堆图像。我使用 MySQL 是因为我有一个专用服务器,并且由于定价原因,使用 firestore 可能不是一个好主意。我希望它有一个无限滚动视图,每次加载 10 张图片,但目前它同时加载所有图片,这让应用感觉非常慢。

这是我的 lib/main.dart

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:http/http.dart' as http;
//local import, you can ignore it
import './nav.dart';
import './detail.dart';
import './placeholder.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyApp createState() => new _MyApp();
}

class _MyApp extends State<MyApp> {
  Future<List> getData() async {
    final resp = await http.get("http://192.168.43.68/API/readImage.php");
    return json.decode(resp.body);
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new MaterialApp(
      theme: new ThemeData.dark(),
      home: Scaffold(
        appBar: new AppBar(
      title: new Text("Title"),
    ),
    drawer: Nav(),
    body: new FutureBuilder(
      future: getData(),
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          print(snapshot.error);
        }

        return snapshot.hasData
            ? new ItemList(
                list: snapshot.data,
              )
            : new Center(child: new CircularProgressIndicator());
      },),),);}}


//Item builder to display each image
class ItemList extends StatelessWidget {
  final List list;
  ItemList({this.list});

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Padding(
      padding: const EdgeInsets.all(0.0),
      child: new StaggeredGridView.countBuilder(
        crossAxisCount: 4,
        itemCount: list.length,
        itemBuilder: (BuildContext context, int index) => new Container(
        child: new GestureDetector(
            onTap: () => Navigator.of(context).push(new MaterialPageRoute(
                builder: (BuildContext context) => new Detail(
                      list: list,
                      index: index,
                    ))),
            child: Card(
              child: new Column(
                children: <Widget>[
                  new Stack(
                    children: <Widget>[
                      FadeInImage.memoryNetwork(
                        placeholder: kTransparentImage,
                        image: list[index]['url'],
                      ),],),

                  new Padding(
                    padding: EdgeInsets.all(4.0),
                    child: new Column(
                      children: <Widget>[
                        new Text(list[index]['name'],
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              color: Colors.white70,
                            ))],),)],),))),
    staggeredTileBuilder: (index) => new StaggeredTile.fit(2),
      ),);}}

这是我的 readImage.php(我仍然不知道该怎么做)

<?php
include 'dbcon.php';
$sth = "SELECT * FROM pict INNER JOIN user ON pict.uid=user.uid LIMIT 10";

$result = $conn->query($sth);
$outp = array();
$outp = $result->fetch_all(MYSQLI_ASSOC);

echo json_encode($outp);

enter code here

仅此而已,我们将不胜感激。

【问题讨论】:

  • 谢谢,它真的很有帮助,然后问题是一次从数据库中加载所有数据可以吗?你知道可能像一个分页并将数据从下一页插入到列表中
  • 不,一次加载所有数据是个坏主意,你需要一个分页
  • yups,所以它就像一个分页,让我们说每次加载 10 个数据,每次更新都将数据添加到现有列表并显示它?所以我需要做一个 void 来获取数据
  • 是的,阅读帖子

标签: android ios mysql dart flutter


【解决方案1】:

我认为您遇到的主要问题是您使用的是 StaggeredTile.fit()。

一些背景信息:在颤振中,图像大小不是立即确定的,而是在图像实际加载后确定的。这对于少量图像来说很好,但是当您拥有大量(可能是无限的)图像时,就会出现问题。

这样做的原因是,当第一次构造列表时,它会布置足够的孩子以适应屏幕(+可能不适用于 StaggeredGridView 但适用于大多数颤动列表的 cacheExtent)。想一想列表中的每个项目将如何布置自己 - GestureDetector、Card、Column 和 Stack 所有代表其子项的大小。所以尺寸取决于图像。占位符并不能真正确定高度,因此您可以将图像视为高度为零或一。

这意味着在您的页面中,随着越来越多的项目添加到屏幕上,它会不断尝试加载越来越多的图像 - 垂直像素数或基本上无限的像素数,具体取决于处理占位符高度的方式.

对此有一个简单的解决方案,但它可能对您没有吸引力 - 使用固定高度而不是使用 StaggeredTile.fit(),然后让您的图像适合该高度。

不幸的是,如果您希望每个图像具有不同的高度,它会变得更加复杂。处理该问题的一种方法(因为您可以控制数据库)是将纵横比与每个图像的路径一起存储在数据库中。这样你就可以用 AspectRatio 小部件包装你的 FaceInImage,因此高度会立即确定。

这只有在您的项目列表当然不是真正无限的情况下才有效,但由于它在数据库中,我认为假设 =D 是相当安全的。您可以在 PHP 中使用the getimagesize function 来计算每张图片的纵横比,然后在整个数据库中运行一次,然后从现在开始,每当您插入新图片时,您都必须计算纵横比。

另一种解决方案是从您自己指定的固定高度开始,然后在加载图像后更改高度。但是,我不知道 StaggeredGridView 会如何处理这个问题——我见过的大多数列表/网格类都希望他们的孩子保持相同的大小。在这种情况下,您可能需要查看 CustomScrollView 并编写自己的条子,这超出了本问题的范围。


编辑:OP 澄清说,显然 MySQL 部分是他们要问的,而不是为什么它很慢。我仍然认为图像是为什么它很慢而不是请求 URL 的原因,但我可能是错的。尚未指定是否正在加载 10、50、100 或 1000 张图像。

如果没有更多关于如何设置数据库的知识,很难就这是否是问题给出明确的答案。但我将简要介绍一种设置服务器的可能方法。

我不会为您的服务器编写实际代码,因为这超出了关于颤振的 SO 问题的范围。如果您无法弄清楚,我建议您先找到有关设置服务器的课程或教程,然后再问一个问题 没有标记为颤振,而是使用 PHP/MySQL 等实际上就是你要问的,关于你遇到的具体问题,而不是笼统的“我帮不了我”,因为这样不会得到答案。


假设如下:

  • 您已经设置了一个数据库,您可以在其中查询 URL、描述等列表
  • 此数据库预计会返回大量值(例如,超过 200 个或其他值)

在服务器端,您必须设置一个端点来响应请求并返回部分数据。如果您想使用 JSON,我希望没有参数的端点返回如下内容:

{
   num: 30,
   images: [
    { title: ..., url: ..., .... },
    ... 
   ],
   more: true
}

并且该列表必须按某些参数排序 - 标题、日期、ID 等。您也可以有一个 totalItems 作为结果的一部分返回,告诉客户端有多少图像。您也可以选择接受要返回的项目数。

对于后续请求,您可以接受参数numoffset。偏移量应该是描述返回的最后一个结果的一种方式,以便查询知道从哪里开始 - 如果您按 ID 排序,它可能是那个,或者按日期它可能是日期。而num 将是要返回的最大结果数。

如果您不返回 totalItems 作为响应的一部分,您可以选择有一个不同的请求,它只为您提供最大数量的项目,因为这可能会让您的生活更轻松一些。如果您不想执行其中任何一项,请查看the link someone posted in a comment,它描述了如何编写无限加载列表。

请注意,这只会返回图像的 URL,而不是图像本身。

接下来,您需要在 Flutter 代码中创建某种系统来缓存。这可能会有点复杂,因为您不仅需要获取图像,还需要在页面滚动时获取图像的描述。

我会怎么做如下:

  • 制作一个分页管理器来处理加载项目的描述
  • 分页管理器可以请求项目,即从 0 开始,编号 30
  • 分页管理器启动此请求并对其进行跟踪
  • 每个单独的列表项都向分页管理器请求其数据
  • 每个列表项都有一个 FutureBuilder,如果数据正在加载,它会显示一些内容,如果数据已加载,则会显示其他内容。
  • 经理知道是否已针对该项目启动了请求,如果没有,它会对该项目 + 及其周围的项目发出请求(这样您就不会一次发送一堆单独的请求)
  • 列表项返回一个只返回其数据的未来,如果数据已经加载或等待数据从服务器返回,则立即完成
  • 在某些时候,如果您有很多图像,您可能希望取消初始化缓存管理器中的数据 - 您可以通过跟踪当前正在请求哪些图像并删除小于 100 或 > 100 的任何图像来做到这一点更高或类似的东西。

还有另一种方法可以做到这一点,但可能不是特别适合您的数据库(取决于它的设置方式)。您可以简单地为每个图像(即 GET user/images/1、user/images/2 等)向服务器发出请求,而不是在客户端进行缓存。然后,您的服务器将在内部确定从何处加载该图像并直接返回它,并将标题等作为标题。

这样做的问题是,幼稚的方法是为每个传入的请求执行数据库请求;这会起作用,但会导致对您的数据库的大量请求。取决于您的数据库设置,这可能很好,但很可能最终会导致问题。相反,您可以在您的服务器上对请求进行批处理(即,如果请求 0,则还获取并缓存 0-30),并简单地对缓存的数据进行处理。我将把它留给你来实施,因为它超出了这个问题的范围。

【讨论】:

  • 它有帮助,但它似乎没有回答我需要知道如何使用 mysql 进行无限滚动的主要问题
  • 我正在处理feels really slow 部分,因为这似乎是主要问题。实际上,您应该能够一次加载超过 10 个项目而不会使应用程序变慢 - 它变慢的原因是我上面概述的,因为正确完成后颤动只会加载当前显示在屏幕上的图像.如果您实际上有infinite 的项目数量,那将是一个问题。但如果它只是一个相当大的数字,我怀疑你发回的 json 几乎和单个图像一样大。
  • 查看我编辑的答案以获得一般描述。但正如我在编辑部分所说,你真的应该打开一个用 mysql 和 php 标记的问题,因为这就是你在服务器端使用的。即使那样,您的问题也很笼统,可能会因此而关闭,因此我建议您尝试使用教程等解决问题,然后再回来询问有关特定问题的问题。
  • 谢谢,不胜感激。我的服务器端完成了
猜你喜欢
  • 2012-02-25
  • 2018-12-26
  • 1970-01-01
  • 2013-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-28
  • 1970-01-01
  • 2021-09-06
相关资源
最近更新 更多