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