Я пытаюсь получить данные из локального хранилища и отобразить их на экране с помощью flutter_bloc, но получаю сообщение об ошибке «тип «String» не является подтипом типа «Map<String, Dynamic>». Я проверил, но не могу найти решение.
Кто-нибудь помогите мне решить эту ошибку...
Ниже мой код...
И я добавил BlockProvider в файл main.dart.
void main() async {
runApp(
MultiBlocProvider(
providers: [
BlocProvider<ResumeTemplatePreviewBloc>(
create: (context) => ResumeTemplatePreviewBloc()),
],
child: const MaterialApp(
home: ResumeTempletePreview(isstart: true),
),
),
);
}
резюме_templete_preview_bloc.dart
class ResumeTemplatePreviewBloc
extends Bloc<ResumeTemplatePreviewEvent, ResumeTemplatePreviewState> {
ResumeTemplatePreviewBloc() : super(ResumeTemplatePreviewInitial()) {
on<LoadResumeData>(_onLoadResumeData);
}
void _onLoadResumeData(
LoadResumeData event, Emitter<ResumeTemplatePreviewState> emit) async {
emit(ResumeTemplatePreviewLoading());
try {
final jsonString = window.localStorage['RESUMEDATA'];
if (jsonString == null || jsonString.isEmpty) {
throw Exception('No resume data found in local storage');
}
final Map<String, dynamic> resumeData = json.decode(jsonString);
log("Decoded resume data: $resumeData");
emit(ResumeTemplatePreviewLoaded(resumeData));
} catch (e) {
log(e.toString());
emit(ResumeTemplatePreviewError(e.toString()));
}
}
}
резюме_templete_preview_event.dart
import 'dart:typed_data';
import 'package:equatable/equatable.dart';
abstract class ResumeTemplatePreviewEvent extends Equatable {
const ResumeTemplatePreviewEvent();
@override
List<Object> get props => [];
}
class LoadResumeData extends ResumeTemplatePreviewEvent {}
class DownloadResume extends ResumeTemplatePreviewEvent {
final Uint8List capturedImage;
const DownloadResume(this.capturedImage);
@override
List<Object> get props => [capturedImage];
}
резюме_templete_preview_state.dart
import 'package:equatable/equatable.dart';
abstract class ResumeTemplatePreviewState extends Equatable {
const ResumeTemplatePreviewState();
@override
List<Object> get props => [];
}
class ResumeTemplatePreviewInitial extends ResumeTemplatePreviewState {}
class ResumeTemplatePreviewLoading extends ResumeTemplatePreviewState {}
class ResumeTemplatePreviewLoaded extends ResumeTemplatePreviewState {
final Map<String, dynamic> resumeData;
const ResumeTemplatePreviewLoaded(this.resumeData);
@override
List<Object> get props => [resumeData];
}
class ResumeTemplatePreviewError extends ResumeTemplatePreviewState {
final String message;
const ResumeTemplatePreviewError(this.message);
@override
List<Object> get props => [message];
}
class ResumeDownloading extends ResumeTemplatePreviewState {}
class ResumeDownloaded extends ResumeTemplatePreviewState {}
class ResumeDownloadError extends ResumeTemplatePreviewState {
final String message;
const ResumeDownloadError(this.message);
@override
List<Object> get props => [message];
}
резюме_templete_preview.dart
import 'dart:convert';
import 'dart:developer';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:html';
import 'package:flutter/material.dart';
import 'package:quick_resume_creator/core/colors/app_colors.dart';
import 'package:quick_resume_creator/core/constants/dimens.dart';
import 'package:quick_resume_creator/models/education.dart';
import 'package:quick_resume_creator/models/employment.dart';
import 'package:quick_resume_creator/models/personal_skill.dart';
import 'package:quick_resume_creator/models/professional_skill.dart';
import 'package:quick_resume_creator/models/skill.dart';
import 'package:quick_resume_creator/screens/home_screen/home_screen.dart';
import 'package:quick_resume_creator/screens/resume_template/resume_template1.dart';
import 'package:quick_resume_creator/screens/resume_template/resume_template2.dart';
import 'package:quick_resume_creator/screens/resume_templete_preview/resume_templete_preview_bloc/resume_templete_preview_bloc.dart';
import 'package:quick_resume_creator/screens/resume_templete_preview/resume_templete_preview_bloc/resume_templete_preview_event.dart';
import 'package:quick_resume_creator/screens/resume_templete_preview/resume_templete_preview_bloc/resume_templete_preview_state.dart';
class ResumeTempletePreview extends StatefulWidget {
final dynamic extra;
final bool isstart;
const ResumeTempletePreview({super.key, this.extra, required this.isstart});
@override
State<ResumeTempletePreview> createState() => _ResumeTempletePreviewState();
}
class _ResumeTempletePreviewState extends State<ResumeTempletePreview> {
String resumeIndex = "";
late ScrollController _scrollController;
@override
void initState() {
_scrollController = ScrollController();
_scrollController.addListener(() {
setState(() {
if (_scrollController.offset >= 300) {
showBackToTopButton = true;
} else {
showBackToTopButton = false;
}
});
});
super.initState();
context.read<ResumeTemplatePreviewBloc>().add(LoadResumeData());
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.authBgcolor,
appBar: _buildappbar(),
body: ListView(
children: [
Divider(color: AppColors.dividercolor, height: 1),
buildSizedBoxH(50),
BlocBuilder<ResumeTemplatePreviewBloc, ResumeTemplatePreviewState>(
builder: (context, state) {
if (state is ResumeTemplatePreviewLoading) {
log("state is ResumeTemplatePreviewLoading");
return const Center(child: CircularProgressIndicator());
} else if (state is ResumeTemplatePreviewLoaded) {
log("state is ResumeTemplatePreviewLoaded");
resumeIndex = state.resumeData['id'] != null &&
state.resumeData['id'] != ""
? state.resumeData['id'].toString()
: "1";
} else if (state is ResumeTemplatePreviewError) {
log("state is ResumeTemplatePreviewError");
return Center(child: Text(state.message));
}
return getResumeTemplate(resumeIndex);
},
),
],
));
}
Widget getResumeTemplate(String status) {
switch (status) {
case '1':
return ResumeTemplate1(
customerFirstNametext:
window.localStorage['CUSTOMERFIRSTNAME'].toString(),
customerLastNametext:
window.localStorage['CUSTOMERLASTNAME'].toString(),
customerProfileImageURL:
window.localStorage['CUSTOMERPROFILEIMAGE'].toString(),
customerProfessiontext:
window.localStorage['CUSTOMERPROFESSION'].toString(),
customerLocationtext:
window.localStorage['CUSTOMERLOCATION'].toString(),
customerWebsitetext:
window.localStorage['CUSTOMERWEBSITE'].toString(),
customerPhoneNotext:
window.localStorage['CUSTOMERPHONENO'].toString(),
customerEmailIDtext:
window.localStorage['CUSTOMEREMAILID'].toString(),
customerProfessionalSummarytext:
window.localStorage['CUSTOMERPROFESSIONALSUMMARY'].toString(),
customerEducationList:
(jsonDecode(window.localStorage['CUSTOMEREDUCATIONLIST']!)
as List<dynamic>)
.map<Education>((item) => Education.fromJson(item))
.toList(),
customerEmploymentList:
(jsonDecode(window.localStorage['CUSTOMEREMPLOYMENTLIST']!)
as List<dynamic>)
.map<Employment>((item) => Employment.fromJson(item))
.toList(),
customerProfessionalSkillList:
(jsonDecode(window.localStorage['CUSTOMERPROFESSIONALSKILLLIST']!)
as List<dynamic>)
.map<ProfessionalSkill>(
(item) => ProfessionalSkill.fromJson(item))
.toList(),
customerPersonalSkillList:
(jsonDecode(window.localStorage['CUSTOMERPERSONALSKILLLIST']!)
as List<dynamic>)
.map<PersonalSkill>((item) => PersonalSkill.fromJson(item))
.toList(),
);
case '2':
return ResumeTemplate2(
customerFirstNametext:
window.localStorage['CUSTOMERFIRSTNAME'].toString(),
customerLastNametext:
window.localStorage['CUSTOMERLASTNAME'].toString(),
customerProfileImageURL:
window.localStorage['CUSTOMERPROFILEIMAGE'].toString(),
customerProfessiontext:
window.localStorage['CUSTOMERPROFESSION'].toString(),
customerLocationtext:
window.localStorage['CUSTOMERLOCATION'].toString(),
customerWebsitetext:
window.localStorage['CUSTOMERWEBSITE'].toString(),
customerPhoneNotext:
window.localStorage['CUSTOMERPHONENO'].toString(),
customerEmailIDtext:
window.localStorage['CUSTOMEREMAILID'].toString(),
customerProfessionalSummarytext:
window.localStorage['CUSTOMERPROFESSIONALSUMMARY'].toString(),
customerEducationList:
(jsonDecode(window.localStorage['CUSTOMEREDUCATIONLIST']!)
as List<dynamic>)
.map<Education>((item) => Education.fromJson(item))
.toList(),
customerEmploymentList:
(jsonDecode(window.localStorage['CUSTOMEREMPLOYMENTLIST']!)
as List<dynamic>)
.map<Employment>((item) => Employment.fromJson(item))
.toList(),
customerSkillList:
(jsonDecode(window.localStorage['CUSTOMERSKILLLIST']!)
as List<dynamic>)
.map<Skill>((item) => Skill.fromJson(item))
.toList(),
);
default:
return ResumeTemplate1(
customerFirstNametext:
window.localStorage['CUSTOMERFIRSTNAME'].toString(),
customerLastNametext:
window.localStorage['CUSTOMERLASTNAME'].toString(),
customerProfileImageURL:
window.localStorage['CUSTOMERPROFILEIMAGE'].toString(),
customerProfessiontext:
window.localStorage['CUSTOMERPROFESSION'].toString(),
customerLocationtext:
window.localStorage['CUSTOMERLOCATION'].toString(),
customerWebsitetext:
window.localStorage['CUSTOMERWEBSITE'].toString(),
customerPhoneNotext:
window.localStorage['CUSTOMERPHONENO'].toString(),
customerEmailIDtext:
window.localStorage['CUSTOMEREMAILID'].toString(),
customerProfessionalSummarytext:
window.localStorage['CUSTOMERPROFESSIONALSUMMARY'].toString(),
customerEducationList:
(jsonDecode(window.localStorage['CUSTOMEREDUCATIONLIST']!)
as List<dynamic>)
.map<Education>((item) => Education.fromJson(item))
.toList(),
customerEmploymentList:
(jsonDecode(window.localStorage['CUSTOMEREMPLOYMENTLIST']!)
as List<dynamic>)
.map<Employment>((item) => Employment.fromJson(item))
.toList(),
customerProfessionalSkillList:
(jsonDecode(window.localStorage['CUSTOMERPROFESSIONALSKILLLIST']!)
as List<dynamic>)
.map<ProfessionalSkill>(
(item) => ProfessionalSkill.fromJson(item))
.toList(),
customerPersonalSkillList:
(jsonDecode(window.localStorage['CUSTOMERPERSONALSKILLLIST']!)
as List<dynamic>)
.map<PersonalSkill>((item) => PersonalSkill.fromJson(item))
.toList(),
);
}
}
}
Это моя консоль отладки...
Restarted application in 244ms.
[log] TypeError: "{\"uid\":\"ryln8SHS9fg7cTE7sTdwS4dzmeH2\",\"id\":\"6\",\"resumeid\":\"fXFhqH02zX8iv8THRVB1\",\"customerFirstNametext\":\"Testing\",\"customerLastNametext\":\"Testing\",\"customerProfileImage\":\"https://firebasestorage.googleapis.com/v0/b/quick-resume-creator.appspot.com/o/profile_images%2Fryln8SHS9fg7cTE7sTdwS4dzmeH2%2FfXFhqH02zX8iv8THRVB1%2F1720696073185.jpg?alt=media&token=8c803ce4-4a98-43f2-b630-ccec214a317f\",\"customerProfessiontext\":\"Testing\",\"customerLocationtext\":\"Testing\",\"customerWebsitetext\":\"www.testing.com\",\"customerPhoneNotext\":\"7894561230\",\"customerEmailIDtext\":\"[email protected]\",\"customerProfessionalSummarytext\":\"TestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTestingTesting.\",\"customerEducationList\":[{\"university\":\"Testing\",\"degree\":\"Testing\",\"startDate\":\"Jul 2023\",\"endDate\":\"Jul 2033\"}],\"customerEmploymentList\":[{\"jobTitle\":\"Testing\",\"companyName\":\"Testing\",\"startDate\":\"Jul 2023\",\"endDate\":\"Jul 2025\",\"address\":\"Testing\"}],\"customerProfessionalSkillList\":[],\"customerPersonalSkillList\":[],\"customerSkillList\":[{\"skill\":\"Testing\",\"level\":60},{\"skill\":\"Testing\",\"level\":40},{\"skill\":\"Testing\",\"level\":40}],\"customerSkillLavel\":0}": type 'String' is not a subtype of type 'Map<String, dynamic>'
[log] state is ResumeTemplatePreviewError
Помогите пожалуйста решить эту ошибку...
Можете ли вы напечатать jsonString
перед вызовом json.decode(jsonString)
, чтобы увидеть фактические данные?
@AlexSunderSingh это напечатано в журналах
[журнал] QuickResumeData (uid: ryln8SHS9fg7cTE7sTdwS4dzmeH2, id: 6, summaryid: fXFhqH02zX8iv8THRVB1, customerFirstNametext: Testing, customerLastNametext: Testing,.....) это журнал перед вызовом 'json.decode(jsonString)' @AlexSunderSingh
Как сказал @pskink, у вашего jsonString
есть "
в начале и конце, возможно, нам придется обрезать его из строки.
ваш jsonString
начинается с "
- он декодируется как String
, а не Map
- вы можете увидеть, как это работает, запустив: import 'dart:convert'; void main() { final d0 = jsonDecode('""'); final d1 = jsonDecode('{}'); final d2 = jsonDecode('"{}"'); print('d0 is String: ${d0 is String}'); print('d1 is Map: ${d1 is Map}'); print('d2 is Map: ${d2 is Map}'); print('d2 is String: ${d2 is String}'); }
в dartpad.dev
и, конечно, вам не следует исправлять это, удаляя начало и конец "
(потому что вам также придется заменить каждый \"
на "
), а вместо этого пытаться выяснить, почему window.localStorage['RESUMEDATA']
содержит такие ошибочные данные - это ваша настоящая основная проблема
Готово, я удалил косые черты и кавычки и передал их значения. Стал работать нормально. Спасибо за советы AlexSunderSingh и pskink изображение кода
нет, это не то, как вам следует это делать, вместо этого вы должны убедиться, что ваши сохраненные данные представляют собой действительную строку json - я имею в виду, что window.localStorage['RESUMEDATA']
должен содержать действительную строку json
Вы имеете в виду, проверьте, откуда в строке json берутся косые черты и кавычки? @pskink
да, именно: вам следует исправить проблему как можно скорее, а не при анализе ваших данных, что, если вам нужно сделать это в другом месте - вы бы повторили свой код с replaceAll
снова и снова?
вы пытаетесь декодировать строку в Map<String, Dynamic>, но это не удается, поскольку строка может быть недопустимым JSON или декодируется неправильно попробуйте эту обработку ошибок.
_onLoadResumeData(LoadResumeData event, Emitter<ResumeTemplatePreviewState> emit) async {emit(ResumeTemplatePreviewLoading());
try {
final jsonString = window.localStorage['RESUMEDATA'];
if (jsonString == null || jsonString.isEmpty) {
throw Exception('No resume data found in local storage');
}
// Log the jsonString for debugging
print("Retrieved resume data JSON: $jsonString");
// Decode jsonString into Map<String, dynamic>
final Map<String, dynamic> resumeData = json.decode(jsonString);
// Log decoded resume data for debugging
print("Decoded resume data: $resumeData");
emit(ResumeTemplatePreviewLoaded(resumeData));
} catch (e) {
print("Error loading resume data: $e");
emit(ResumeTemplatePreviewError(e.toString()));
}
}
Ошибка BlocBuilder: Ошибка: неожиданное нулевое значение в BlocBuilder<ResumeTemplatePreviewBloc, ResumeTemplatePreviewState>. Причина: Значение блока равно нулю. || Ошибка синтаксического анализа JSON: Ошибка: TypeError, указывающая, что строка не является подтипом Map<String, Dynamic>. Причина. Полученные данные JSON интерпретируются неправильно, возможно, из-за неправильного формата JSON или неправильной логики анализа.
Ваш jsonString
содержит "
в начале и конце, поэтому, если вы уверены, что строка начинается и заканчивается "
, вам нужно обрезать ее вручную.
try {
String? jsonString = window.localStorage['RESUMEDATA'];
if (jsonString == null || jsonString.isEmpty) {
throw Exception('No resume data found in local storage');
}
if (jsonString.startsWith('"')){
jsonString = jsonString.substring(1);
}
if (jsonString.endsWith('"')){
jsonString = jsonString.substring(0, jsonString.length - 1);
}
jsonString = jsonString.replaceAll(r'\"', '"');
final Map<String, dynamic> resumeData = json.decode(jsonString);
log("Decoded resume data: $resumeData");
emit(ResumeTemplatePreviewLoaded(resumeData));
} catch (e) {
log(e.toString());
emit(ResumeTemplatePreviewError(e.toString()));
}
Попробуйте использовать этот фрагмент в своем классе ResumeTemplatePreviewBloc
ваш
jsonString
начинается (и заканчивается) на"
, поэтому он декодируется какString
, а неMap