如何才能先显示加载屏幕,然后获取数据?

问题描述 投票:0回答:1

我遇到了一个问题,即正在获取的数据量导致应用程序稍微滞后。没什么大不了的,只有半秒钟。我怎样才能将其调整到显示加载屏幕的位置,然后开始获取数据。

import 'package:flutter/material.dart';
import 'package:manebenefitsstudent/constants/colors.dart';
import 'package:manebenefitsstudent/services/database/business_model.dart';
import 'package:manebenefitsstudent/services/database/data_provider.dart';
import 'package:manebenefitsstudent/widgets/reusable/card_data.dart';
import 'package:manebenefitsstudent/widgets/reusable/card_widget.dart';
import 'package:manebenefitsstudent/widgets/reusable/loading/loading_screen.dart';
import 'package:provider/provider.dart';

class RestaurantsView extends StatefulWidget {
  const RestaurantsView({super.key});

  @override
  State<RestaurantsView> createState() => _RestaurantsViewState();
}

class _RestaurantsViewState extends State<RestaurantsView> {
  bool _isLoading = true;
  List<Business> _restaurants = [];

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

  Future<void> _fetchBusinesses() async {
    await Future.wait([
      Future.delayed(const Duration(milliseconds: 1500)),
      Provider.of<DataProvider>(context, listen: false)
          .getBusinessesByCategory(3)
    ]).then((results) {
      setState(() {
        _restaurants = results[1] as List<Business>;
        _isLoading = false;
      });
    }).catchError((error) {
      setState(() {
        _isLoading = false;
      });
      print('Error fetching businesses: $error');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Restaurants'),
        backgroundColor: unaGrey,
      ),
      body: _isLoading
          ? const LoadingScreen(
              loadingText: 'LOADING RESTAURANTS...',
              minDisplayTime: 1500,
            )
          : ListView.builder(
              itemCount: _restaurants.length,
              itemBuilder: (context, index) {
                var business = _restaurants[index];
                return CustomCard(
                  cardData: CardData(
                    imageData: business.image,
                    facebookUrl: business.facebookUrl,
                    instagramUrl: business.instagramUrl,
                    websiteUrl: business.websiteUrl,
                    directionsUrl: business.directionsUrl,
                  ),
                );
              },
            ),
    );
  }
}

获取数据只需要大约半秒,但应用程序会在那一刻冻结。或者有没有更好的方法从应用程序中的 sqf 数据库获取数据?

这是加载屏幕:

import 'package:flutter/material.dart';
import 'package:gif/gif.dart';
import 'package:manebenefitsstudent/constants/colors.dart';

class LoadingScreen extends StatefulWidget {
  final String loadingText;
  final int minDisplayTime;

  const LoadingScreen(
      {super.key, this.loadingText = 'LOADING...', this.minDisplayTime = 1000});

  @override
  State<LoadingScreen> createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen>
    with SingleTickerProviderStateMixin {
  late GifController _gifController;

  @override
  void initState() {
    super.initState();
    _gifController = GifController(vsync: this);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      int frameCount = 16;
      _gifController.repeat(
          min: 0, max: frameCount - 15, period: const Duration(seconds: 1));
    });
  }

  @override
  void dispose() {
    _gifController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: unaGrey,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Gif(
              controller: _gifController,
              image: const AssetImage('assets/images/lion_running.gif'),
              width: 300,
              height: 300,
            ),
            const SizedBox(height: 20),
            const CircularProgressIndicator.adaptive(
              valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
            ),
            const SizedBox(height: 20),
            Text(
              widget.loadingText,
              style: const TextStyle(
                color: Colors.white,
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

这是用于从数据库获取所有数据的代码:

数据初始化器:

import 'dart:io';
import 'package:manebenefitsstudent/services/database/business_model.dart';
import 'package:path/path.dart';
import 'package:http/http.dart' as http;
import 'package:manebenefitsstudent/services/database/database_helper.dart';
import 'package:sqflite/sqflite.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

class DataInitializer {
  static const String dbUrl =
      'GH REPO';
  static const String dbVersionUrl = '${dbUrl}db_version.txt';
  static const String dbFileName = 'manebenefitsdb.db';
  static String? githubToken = dotenv.env['GITHUB_TOKEN'];

  static Future<void> initializeData() async {
    print('Initializing data...');
    await _updateDatabaseIfNeeded();
  }

  static Future<void> _updateDatabaseIfNeeded() async {
    String databasesPath = await getDatabasesPath();
    String path = join(databasesPath, dbFileName);

    bool exists = await databaseExists(path);
    if (exists) {
      int localDbVersion = await _getLocalDbVersion(path);
      int remoteDbVersion = await _fetchRemoteDbVersion();
      print('Local DB version: $localDbVersion');
      print('Remote DB version: $remoteDbVersion');
      if (localDbVersion >= remoteDbVersion) {
        print('Local database is up-to-date.');
        return;
      }
    }

    print('Downloading database...');
    final response = await http.get(
      Uri.parse('${dbUrl}manebenefitsdb.db'),
      headers: {
        'Authorization': 'token $githubToken',
      },
    );
    print(
        'HTTP GET request to ${dbUrl}manebenefitsdb.db responded with status code: ${response.statusCode}');
    if (response.statusCode == 200) {
      await File(path).writeAsBytes(response.bodyBytes, flush: true);
      print('Database downloaded and saved.');
    } else {
      throw Exception('Failed to download database');
    }
  }

  static Future<int> _getLocalDbVersion(String path) async {
    final db = await openDatabase(path);
    try {
      List<Map<String, dynamic>> result =
          await db.rawQuery('SELECT version_number FROM version LIMIT 1');
      print('Local DB version query result: $result');
      return result.isNotEmpty ? result.first['version_number'] as int : 0;
    } catch (e) {
      print('Error getting local database version: $e');
      return 0;
    } finally {
      await db.close();
    }
  }

  static Future<int> _fetchRemoteDbVersion() async {
    final response = await http.get(
      Uri.parse(dbVersionUrl),
      headers: {
        'Authorization': 'token $githubToken',
      },
    );
    print(
        'HTTP GET request to $dbVersionUrl responded with status code: ${response.statusCode}');
    if (response.statusCode == 200) {
      print('Remote DB version fetched: ${response.body.trim()}');
      return int.parse(response.body.trim());
    } else {
      throw Exception('Failed to fetch remote database version');
    }
  }

  static Future<List<Business>> getBusinessesByCategory(int categoryId) async {
    DatabaseHelper dbHelper = DatabaseHelper();
    List<Map<String, dynamic>> businesses =
        await dbHelper.getBusinessesByCategory(categoryId);

    print('Fetched businesses for category $categoryId: $businesses');

    List<Business> businessList = businesses.map((map) {
      return Business.fromMap(map);
    }).toList();

    print('Converted businesses for category $categoryId: $businessList');

    businessList.sort((a, b) => a.name.compareTo(b.name));

    return businessList;
  }
}

class GlobalData {
  static List<Business> businesses = [];
}

数据库助手:

import 'dart:io';
import 'package:flutter/services.dart' show ByteData, rootBundle;
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

class DatabaseHelper {
  static final DatabaseHelper _instance = DatabaseHelper._internal();
  static Database? _database;

  factory DatabaseHelper() {
    return _instance;
  }

  DatabaseHelper._internal();

  Future<Database> get database async {
    if (_database != null) return _database!;

    _database = await _initDatabase();
    return _database!;
  }

  Future<Database> _initDatabase() async {
    String databasesPath = await getDatabasesPath();
    String path = join(databasesPath, 'manebenefitsdb.db');

    bool exists = await databaseExists(path);
    if (!exists) {
      ByteData data = await rootBundle.load('assets/manebenefitsdb.db');
      List<int> bytes =
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      await File(path).writeAsBytes(bytes, flush: true);
    }

    return await openDatabase(path);
  }

  Future<List<Map<String, dynamic>>> getBusinessesByCategory(
      int categoryId) async {
    final db = await database;
    try {
      final result = await db.rawQuery('''
        SELECT b.*
        FROM Businesses b
        INNER JOIN Business_categories bc ON b.Business_id = bc.Business_id
        WHERE bc.Category_id = ?
      ''', [categoryId]);
      print('Query result: $result'); 
      return result;
    } catch (e) {
      print('Error querying database: $e');
      return [];
    }
  }
}

数据提供者:

import 'package:flutter/material.dart';
import 'package:manebenefitsstudent/services/database/data_initializer.dart';
import 'package:manebenefitsstudent/services/database/business_model.dart';

class DataProvider extends ChangeNotifier {
  final Map<int, List<Business>> _businessesByCategory = {};

  Future<List<Business>> getBusinessesByCategory(int categoryId) async {
    if (_businessesByCategory.containsKey(categoryId)) {
      return _businessesByCategory[categoryId]!;
    } else {
      List<Business> businesses =
          await DataInitializer.getBusinessesByCategory(categoryId);
      _businessesByCategory[categoryId] = businesses;
      return businesses;
    }
  }
}

我尝试过这样,但我想让它显示我拥有的gif。

import 'package:flutter/material.dart';
import 'package:manebenefitsstudent/constants/colors.dart';
import 'package:manebenefitsstudent/services/database/business_model.dart';
import 'package:manebenefitsstudent/services/database/data_provider.dart';
import 'package:manebenefitsstudent/widgets/reusable/card_data.dart';
import 'package:manebenefitsstudent/widgets/reusable/card_widget.dart';
import 'package:provider/provider.dart';

class RestaurantsView extends StatelessWidget {
  const RestaurantsView({super.key});

  Future<List<Business>> _fetchBusinesses(BuildContext context) async {
    await Future.delayed(const Duration(milliseconds: 1500));
    return Provider.of<DataProvider>(context, listen: false).getBusinessesByCategory(3);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Restaurants'),
        backgroundColor: unaGrey,
      ),
      body: FutureBuilder<List<Business>>(
        future: _fetchBusinesses(context),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          } else if (snapshot.hasError) {
            return Center(
              child: Text('Error: ${snapshot.error}'),
            );
          } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
            return const Center(
              child: Text('No restaurants available'),
            );
          } else {
            var restaurants = snapshot.data!;
            return ListView.builder(
              itemCount: restaurants.length,
              itemBuilder: (context, index) {
                var business = restaurants[index];
                return CustomCard(
                  cardData: CardData(
                    imageData: business.image,
                    facebookUrl: business.facebookUrl,
                    instagramUrl: business.instagramUrl,
                    websiteUrl: business.websiteUrl,
                    directionsUrl: business.directionsUrl,
                  ),
                );
              },
            );
          }
        },
      ),
    );
  }
}
flutter dart lazy-loading sqflite
1个回答
0
投票

FutureBuilder 是正确的小部件,只需放置您的加载视图而不是 CircularProgressIndicator,并且为了有更多时间显示您的 GIF,只需在获取和返回数据的方法上添加 Future.delayed 您可以使用类似这样的东西..

class _MyWidgetState extends State<MyWidget> {
  late Future<List<Business>> businessFuture; 

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    businessFuture = Provider.of<DataProvider>(context, listen: false).getBusinessesByCategory(3);
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Business>>(
      future: businessFuture,
      builder: ((context, snapshot) {
        if (snapshot.connectionState == ConnectionState.none ||
            snapshot.connectionState == ConnectionState.waiting) {
          return LoadingScreen(); // Your GIF
        } else {
          if (snapshot.hasError) {
            return SomeErrorWidget();
          } else {
            // Check your data here
          }
        }
      }),
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.