서버 샘플 소스는 Android 앱 샘플 개발시 사용했던 코드를 가지고 Android Retrofit 라이브러리를 사용할 때와 비교하면서 시도를 해보는 중이다.
factory 생성자를 수동으로 생성하고 내 마음대로 코드를 이렇게 하면 되겠다 싶어 처리했더니 죽어도 해결이 안되었다.
Flutter 에서 JSON 데이터 가져오는 것이 왜 이리 힘들어 ㅠㅠㅠ 하면서 맨붕에 빠졌다가 차분하게 유투브 동영상에 나온 예제를 그대로 따라하면서 살펴보고 문제가 뭔지 비교 분석을 했다.
직집 구현한 factory 생성자
class ContactResult {
final String status;
final String message;
final List<Contact_Item> addrinfo;
const ContactResult({
required this.status,
required this.message,
required this.addrinfo,
});
factory ContactResult.fromJson(Map<String, dynamic> map) {
return ContactResult(
status: map['status'] as String,
message: map['message'] as String,
addrinfo: List<Contact_Item>.from(map['addrinfo']),
);
}
}
|
final List<Contact_Item>? addrinfo; 라고 해야 하는데 강제로 null 값을 제거하고 동작 결과를 확인하기 위해 시도했으나 해결되지 않았다.
에러메시지를 구글링 해보니 addrinfo: List<Contact_Item>.from(map['addrinfo']) 로 하면 해결될 것처럼 써있는 답변이 있어서 시도해봤다. 하지만 여전히 에러가 발생한다.
자동 생성한 factory 생성자
Json Serializable 을 이용하여 자동 생성한 factory 생성자 결과
ContactResult _$ContactResultFromJson(Map<String, dynamic> json) =>
ContactResult(
status: json['status'] as String,
message: json['message'] as String,
addrinfo: (json['addrinfo'] as List<dynamic>?)
?.map((e) => Contact_Item.fromJson(e as Map<String, dynamic>))
.toList(),
);
|
위 코드와 아래 자동 생성된 코드를 비교해보면 addrinfo 변수를 처리한 결과가 확연하게 다른 것을 확인할 수 있다.
정상적으로 처리되고 나서 Contact_Item 변수에 오류가 있다는 것도 알게 되었다.
정교하게 변수 처리를 해주지 않으면 에러를 뱉어내는 걸 확인했고, 화면 출력된 결과를 보면서 제대로 수정했다.
import 'package:json_annotation/json_annotation.dart';
part 'contact_item.g.dart';
@JsonSerializable()
class Contact_Item {
final int idx; // String 으로 변수를 선언했는데, 출력 결과에서 int 라고 변경 요청
final String userNM;
final String mobileNO;
final String? telNO;
final String? photo; // 출력 결과에 null 값이 존재하는 걸 확인하고 변경
final bool checkBoxState;
const Contact_Item({
required this.idx,
required this.userNM,
required this.mobileNO,
this.telNO,
this.photo,
required this.checkBoxState,
});
factory Contact_Item.fromJson(Map<String, dynamic> json) =>
_$Contact_ItemFromJson(json);
Map<String, dynamic> toJson() => _$Contact_ItemToJson(this);
}
|
위와 같이 모델 class 를 선언하고 터미널 창에서 dart run build_runner build 를 하면 자동으로 contact_item.g.dart 파일이 생성된다. 코드를 수정시에는 항상 dart run build_runner build 를 해서 업데이트 해줘야 한다.
import 'package:json_annotation/json_annotation.dart';
import 'package:login_ex/contact/model/contact_item.dart';
part 'contact_result.g.dart';
@JsonSerializable()
class ContactResult {
final String status;
final String message;
final List<Contact_Item>? addrinfo;
const ContactResult({
required this.status,
required this.message,
this.addrinfo,
});
factory ContactResult.fromJson(Map<String, dynamic> json)
=> _$ContactResultFromJson(json); Map<String, dynamic> toJson() => _$ContactResultToJson(this);
}
|
json_serializable 는 https://pub.dev/packages/json_serializable/install 를 보면서 라이브러리를 설치해주면 된다.
https://pub.dev/packages/json_annotation/install 를 참조하여 설치한다.
https://pub.dev/packages/build_runner/install 를 참조하여 설치한다.
위 3개의 라이브러를 터미털 창에서 아래 코드를 한줄씩 실행하면 최신버전으로 설치된다.
기존에 설치된 라이브러리 버전이 낮다면 해당 줄을 삭제하고 다시 실행하면 최신버전으로 설치된다.
flutter pub add json_annotation
flutter pub add dev:json_serializable
flutter pub add dev:build_runner
|
그러면 실제 샘플로 구현한 코드를 살펴보자.
import 'package:dio/dio.dart';
import 'package:login_ex/common/repository/retrofit_url.dart';
import 'package:login_ex/contact/model/contact_request.dart';
import 'package:login_ex/contact/model/contact_result.dart';
import 'package:login_ex/common/repository/logging.dart';
abstract class ContactRepo {
Future<ContactResult> getContactList(ContactRequest req);
}
class ContactService extends ContactRepo {
Future<ContactResult> getContactList(ContactRequest req) async {
BaseOptions options = BaseOptions(
baseUrl: RetrofitURL.baseUrl,
);
Dio dio = Dio(options);
dio.interceptors.add(LoggingInterceptor());
FormData formData = FormData.fromMap({
"keyword": req.keyword,
"search": req.search,
});
final response = await dio.post(RetrofitURL.contactData, data: formData);
print(response);
// print(response.data.runtimeType);
//print(response.headers);
if (response.statusCode == 200) {
// final Map<String, dynamic> body = jsonDecode(response.data);
ContactResult result = ContactResult.fromJson(response.data);
return result;
} else {
return ContactResult(status: "fail", message: "fail", addrinfo: []);
}
}
}
|
로그 화면에서 결과를 확인하기 위한 코드 예시이다.
class MainScreen extends StatefulWidget {
const MainScreen({Key? key}) : super(key: key);
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
final ContactRepo repo = ContactService();
@override
void initState() {
super.initState();
getContactData();
}
Future<void> getContactData() async {
ContactRequest dataPost = ContactRequest(
keyword: Crypto.AES_encrypt(Crypto.URLkey()),
search: '',
);
ContactResult response = await repo.getContactList(dataPost);
for(var item in response.addrinfo as List<Contact_Item>){
print('${item.idx} | ${item.userNM} | ${item.mobileNO} | ${item.photo}');
}
}
@override
Widget build(BuildContext context) {
return DefaultLayout(
child: Center(
child: Text('Main Page'),
),
);
}
}
|
keyword는 서버에서 key값을 비교하여 일치하는 경우에만 JSON 결과 데이터를 반환하도록 처리하기 위해서 추가한 것이다.
'Flutter 앱 > Flutter Basic' 카테고리의 다른 글
Flutter 기본 추가 라이브러리 (0) | 2024.01.12 |
---|---|
Flutter TIP 모음 (0) | 2024.01.04 |
Flutter Person freezed 자동완성 예제 (0) | 2023.12.09 |
Flutter Go_Router 버전업에 따른 수정사항 (0) | 2023.12.04 |
Flutter Model Class JSON Serialize g.dart 자동 생성 (1) | 2023.11.21 |