flutter Infinite Scroll View with MySQL

flutter Infinite Scroll View with MySQL



Recently i worked on a gallery like project that display a bunch of image from database. I'm using MySQL because I have a dedicated server and using firestore may not a great idea due to pricing. I want it to have an infinite scroll view that load 10 images each time, but currently it loads all the images at the same time and it makes the app felt really slow.



here is my 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),
),);



and here is my readImage.php (i still got no idea what to do)


<?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



so that's all, any response will be appreciated.





Take a look at this post : marcinszalek.pl/flutter/infinite-dynamic-listview
– diegoveloper
Aug 23 at 15:11





thanks, it really helps, and then the thing is is it okay to just load all the data from the database at once? you know maybe like a pagination and insert the data from next page to the list
– Anang M
Aug 23 at 15:23






no, it's a bad idea to load all the data in one time, you need a pagination
– diegoveloper
Aug 23 at 15:26





yups, so it's just like a pagination and lets says that load 10 data each time, and every update add the data to existing list and display it? so i need to make a void to fetch the data
– Anang M
Aug 23 at 15:30





yes, read the post
– diegoveloper
Aug 23 at 15:31




1 Answer
1



I believe the main issue you're having is that you're using StaggeredTile.fit().



A bit of background information: in flutter, the image size isn't something that gets determined right away but rather once the image has actually loaded. This is fine for small number of images, but when you have a large (potentially infinite) number it causes problems.



The reason for this is that when the list is first constructed, it lays out enough children to fit the screen ( + the cacheExtent which might not apply to StaggeredGridView but does to most of the flutter lists). Think about how each item in the list will lay itself out - the GestureDetector, Card, Column, and Stack all delegate sizing to their children. So the size becomes dependent on the image. The placeholder doesn't really determine the height, so you can think of the image of having a height of zero or one.



That means that in your page, it keeps trying to load more and more images as more and more items are added to the screen - either the number of pixels vertically or essentially infinite depending on how exactly the height of your placeholder is treated.



There is a simple solution to this, but it might not appeal to you - instead of using StaggeredTile.fit(), use a fixed height and then have your images fit themselves within that height.



Unfortunately, it gets a lot more complicated if you want each of the images to have a different height. One of the ways of dealing with that (since you have control over the database) would be to store an aspect ratio along with each image's path in your database. That way you could wrap your FaceInImage with an AspectRatio widget and therefore the height would be determined immediately.



This would only work if your list of items isn't truly infinite of course, but since it's in a database I think that'd be fairly safe to assume =D. You could use the getimagesize function in PHP to figure out the aspect ratio of each image, run through the entire database once doing that, and then from now on whenever you insert a new image you'd have to calculate the aspect ratio.



Another solution would be to start with a fixed height you specify yourself, then change the height once the image is loaded. However, I don't know how well StaggeredGridView would deal with that - most of the list/grid classes I've seen expect their children to stay the same size. In that case you would potentially have to look into a CustomScrollView and writing your own sliver, which is way outside the scope of this question.



EDIT: OP clarified that apparently the MySQL part is what they're asking about rather than why it's slow. I still think that the images is why it's slow rather than the request for the URLs, but I could be wrong. It hasn't been specified whether 10, 50, 100, or 1000's of images are being loaded.



Without more knowledge about how the database is set up, it's hard to give a clear answer for whether that is the issue or not. But I'll write a quick overview of a possible way to set up the server.



I won't write the actual code for your server as that's way outside the scope of a SO question about flutter. If you can't figure that out, I'd advise finding a course or tutorial on getting a server set up, following that, then afterwards asking a question not tagged with flutter but rather with PHP/MySQL etc as that would actually be what you're asking about, about the specific problem you're having rather than a general "I can't do it help me" as that won't get an answer on SO.



Assuming the following:



On the server side, you're going to have to set up an endpoint that responds to requests and returns sections of the data. I'd expect the endpoint with no parameters to return something like the following if you want to use JSON:



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



And that list would have to be sorted by some parameter - title, date, id, etc. You could alternatively have a totalItems that your return as part of the result that tells the client how many images there are. And you could optionally accept the number of items to return as well.


totalItems



For subsequent request, you could accept parameters num, and offset. The offset should be a way of describing the last result returned so that the query knows where to start from - if you're sorting by an ID it could be that, or by date it could be the date. And num would be the maximum number of results to return.


num


offset


num



If you don't return totalItems as part of the response, you could optionally have a different request that just gives you the maximum number of items as that might make your life a bit easier. If you don't want to do either of those, then take a look at the link someone posted in a comment that describes how to write an infinitely loading list.



Note that this would only ever be returning the URLs for the images rather than the images themselves.



Next, you would need to make some sort of system for caching in your flutter code. This could get a little bit complicated, as you not only have to fetch the images but also the description of the images as the page scrolls.



How I would do it is as follows:



There is one other way you could do this, but might not be particularly optimal for your database (depending on how it's set up). Instead of doing the caching on your client side, you could simply do requests to your server for each image (i.e. GET user/images/1, user/images/2, etc). Then your server would internally figure out where to load that image from and would return it directly, with title etc as headers.



The problem with this is that the naive approach would be to do a database request for each and every single request that comes in; this would work but would result in a high number of requests to your database. Depending on your database setup that could be fine, but most likely would cause problems eventually. Instead, you could do batching of requests on your server (i.e. if request 0, also get and cache 0-30), and simply do the processing on the cached data. I'll leave that to you to implement though as it's way outside the scope of this question.





it help, but it doesn't seem to answer the main question that i need to know how to make an infinite scroll with mysql
– Anang M
Aug 24 at 14:03





I was dealing with the feels really slow part, as that seemed the primary problem. And realistically, you should be able to load many more than 10 items at once without making the app slow - the reason it's getting slow is what I outlined above as when done properly flutter will only load the images that are currently being shown on the screen. If you actually have an infinite number of items, that's going to be an issue. But if it's simply a fairly large number, I doubt the json you're sending back is nearly as large as even a single image.
– rmtmckenzie
Aug 24 at 18:07


feels really slow


infinite





See my edited answer for a general description. But as I said in the edited part, you should really open a question tagged with mysql and php as that's what you're using for the server side. Even then, your question is pretty general and will probably be closed as such, so I'd advise trying to figure it out using tutorials etc and then coming back to ask questions about a specific problem.
– rmtmckenzie
Aug 24 at 18:12





thanks, appreciate it. I was done with my server side
– Anang M
Aug 25 at 2:58






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)