这是我的代码
import 'package:flutter/material.dart';
import 'package:mobile_smarcerti/app/modules/sertifikasi/views/detail_sertifikasi_body.dart';
import 'package:mobile_smarcerti/app/modules/sertifikasi/views/detail_sertifikasi_page.dart';
import 'package:mobile_smarcerti/pages/upload_sertifikasi_dosen.dart';
import 'package:mobile_smarcerti/services/api_service.dart';
class SertifikasiBody extends StatefulWidget {
const SertifikasiBody({super.key});
@override
__SertifikasiScreenState createState() => __SertifikasiScreenState();
}
class __SertifikasiScreenState extends State<SertifikasiBody> {
late Future<List<dynamic>> _sertifikasiFuture;
@override
void initState() {
super.initState();
_sertifikasiFuture = ApiService().fetchSertifikasi();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Search',
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
fillColor: const Color.fromARGB(145, 255, 249, 249),
filled: true,
),
),
),
const SizedBox(width: 10),
Container(
height: 54,
width: 48,
decoration: BoxDecoration(
color: const Color.fromARGB(145, 255, 249, 249),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.black),
),
child: IconButton(
icon: const Icon(Icons.filter_list),
color: Colors.grey[700],
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Filter Options"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: const Text("Filter 1"),
onTap: () => Navigator.pop(context),
),
ListTile(
title: const Text("Filter 2"),
onTap: () => Navigator.pop(context),
),
ListTile(
title: const Text("Filter 3"),
onTap: () => Navigator.pop(context),
),
],
),
);
},
);
},
),
),
],
),
const SizedBox(height: 10),
Expanded(
child: FutureBuilder<List<dynamic>>(
future: _sertifikasiFuture,
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 data available'));
} else {
final sertifikasis = snapshot.data!;
return ListView.builder(
itemCount: sertifikasis.length,
itemBuilder: (context, index) {
final sertifikasi = sertifikasis[index];
return Card(
color: Colors.white,
margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 10),
child: ListTile(
leading: const Icon(
Icons.library_books,
size: 35.0,
color: Color.fromARGB(255, 55, 94, 151),
),
title: Text(
sertifikasi['nama_sertifikasi'],
style: const TextStyle(
fontFamily: 'Poppins',
fontSize: 16,
color: Color.fromARGB(255, 55, 94, 151),
fontWeight: FontWeight.bold,
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailSertifikasi(
idSertifikasi: sertifikasi['id_sertifikasi'],
),
),
);
},
trailing: const Icon(
Icons.arrow_forward_ios,
size: 20.0,
color: Color.fromARGB(255, 55, 94, 151),
),
contentPadding: const EdgeInsets.all(20),
),
);
},
);
}
},
),
),
],
),
),
);
}
}
这是我的 api_service 代码
// lib/services/api_service.dart
import 'package:dio/dio.dart';
import 'package:mobile_smarcerti/app/utils/constant.dart';
import 'package:mobile_smarcerti/app/utils/dio_interceptors.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ApiService {
late Dio _dio;
ApiService() {
_dio = Dio(
BaseOptions(
baseUrl: ApiConstants.baseUrl,
connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 3),
validateStatus: (status) {
return status! < 500;
},
),
);
_dio.interceptors.add(DioInterceptor());
}
Future<Response> get(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
try {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('auth_token');
final response = await _dio.get(
path,
queryParameters: queryParameters,
options: Options(headers: {
'Authorization': 'Bearer $token',
'Accept': 'application/json',
if (options?.headers != null) ...options!.headers!,
}),
);
return response;
} on DioException catch (e) {
throw _handleError(e);
}
}
Future<Response> post(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
try {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('auth_token');
final response = await _dio.post(
path,
data: data,
queryParameters: queryParameters,
options: Options(
headers: {
'Authorization': 'Bearer $token',
'Accept': 'application/json',
if (options?.headers != null) ...options!.headers!,
},
),
);
return response;
} on DioException catch (e) {
throw _handleError(e);
}
}
Exception _handleError(DioException e) {
if (e.type == DioExceptionType.connectionTimeout) {
return Exception('Connection timeout');
}
if (e.type == DioExceptionType.receiveTimeout) {
return Exception('Unable to connect to the server');
}
if (e.type == DioExceptionType.unknown) {
return Exception('Something went wrong');
}
return Exception(e.message);
}
Future<List<dynamic>> fetchSertifikasi() async {
try {
final response = await _dio.get('/sertifikasis/');
if (response.data['success']) {
return response.data['data'];
} else {
throw Exception('Failed to load sertifikasi');
}
} catch (e) {
throw Exception('Failed to load sertifikasi: $e');
}
}
我尝试过使用该认证功能创建一个新的 flutter 项目,它工作正常,但当我尝试我的主项目时,它不起作用
我尝试解决这个问题3个小时,结果还是一样。
这是我的虚拟电话中的错误:
Error: Exception: Failed to load sertifikasi: type 'String' is not a subtype of type 'int' of 'index'
这是调试控制台中的错误:
D/EGL_emulation(17071): app_time_stats: avg=426.41ms min=6.15ms max=6485.81ms count=16
W/WindowOnBackDispatcher(17071): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(17071): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation(17071): app_time_stats: avg=28.53ms min=4.21ms max=433.69ms count=29
“String”类型不是“index”的“int”类型的子类型当您尝试从键或索引预计为 int 类型的映射或列表中访问值时,通常会遇到这种情况,但是您“重新提供一个字符串(反之亦然)。在您的代码中,问题可能出在 fetchSertifikasi 方法中如何解析 API 响应数据。
可能的问题是:
在 fetchSertifikasi 中,您将返回 response.data['data'],假设它包含动态对象列表(如地图)。但是,在您的主项目中,数据字段可能没有预期的结构,或者某些字段(例如 id_sertifikasi)可能没有正确的数据类型(例如,是 String 而不是 int)。
调试步骤
第 1 步:记录 API 的响应以查看其确切结构并确认数据类型。
第2步:确保数据类型一致 如果 API 将 id_sertifikasi 作为字符串而不是 int 返回,您应该修改处理此数据的方式。
第3步:检查JSON解析 如果您期望 API 提供特定数据类型,请使用模型类来解析和验证 JSON