해결된 질문
작성
·
205
1
안녕하세요.
처음부터 List<ContactItem> 으로 데이터를 반환받아서 처리해야 하는 것인지, 아니면 아래 코드에서 분기처리할 방법이 있는지 궁금합니다.
import 'package:json_annotation/json_annotation.dart';
import 'package:retrofit_ex2/model/contact_item.dart';
part 'contact_result.g.dart';
@JsonSerializable()
class ContactResult {
final String status;
final String message;
final List<ContactItem>? 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);
}
import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
import 'package:retrofit_ex2/common/repository/retrofit_url.dart';
import 'package:retrofit_ex2/model/contact_result.dart';
part 'rest_client.g.dart';
@RestApi(baseUrl: RetrofitURL.baseUrl)
abstract class RestClient {
factory RestClient(Dio dio, {String baseUrl}) = _RestClient;
@GET(RetrofitURL.contactData)
Future<ContactResult> getContactList();
}
class ContactListPage extends StatefulWidget {
const ContactListPage({Key? key}) : super(key: key);
@override
State<ContactListPage> createState() => _ContactListPageState();
}
class _ContactListPageState extends State<ContactListPage> {
late final RestClient restClient;
@override
void initState() {
Dio dio = Dio();
restClient = RestClient(dio);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<ContactResult>(
future: restClient.getContactList(),
builder: (BuildContext context, AsyncSnapshot<ContactResult> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
final ids = snapshot.data as ContactResult;
//print(ids.runtimeType);
if (ids.status.contains("success")) {
final addrinfo = ids.addrinfo as List<ContactItem>;
print('addrinfo_count ::: ${addrinfo.length}'); // 15개
for(ContactItem item in addrinfo){
print('${item.idx} | ${item.userNM} | ${item.mobileNO} | ${item.photo}'); // 여기서 출력은 잘 됨.
}
return ListView.builder(
itemCount: addrinfo.length,
itemBuilder: (context, index) {
// 총 15개의 List 데이터를 출력하기 위해서 어떻게 해야하는지요?
return Text('');
},
);
} else {
return const Center(
child: Text('에러가 발생했습니다.'),
);
}
},
),
);
}
Widget _contactListWidget(ContactItem item) {
return Column(
children: [
Text(item.idx.toString()),
Text(item.userNM),
Text(item.mobileNO),
Text(item.telNO!),
Text(item.photo!),
],
);
}
}
15개의 데이터를 GET으로 가져오는 것까지는 잘 되는 걸 확인했습니다.
JSON 데이터 전체는 ContactResult 이고, addrinfo 는 List<ContactItem> 입니다.
ContactItem 15개를 ListView.builder 를 이용하여 출력하려고 하는데 어떻게 해야 되는지 몰라 도움 요청드립니다.
답변 1
1
안녕하세요
Q1) 처음부터 List<ContactItem> 으로 데이터를 반환받아서 처리해야 하는 것인지, 아니면 아래 코드에서 분기처리할 방법이 있는지 궁금합니다.
통신 성공 여부를 분기 처리하는 방법에 대한 질문으로 이해했습니다. 작성해주신 것 처럼 FutureBuilder 내부에서 분기처리를 하여 구현하실 수도 있으나, 이 경우 주의 사항이 있습니다.
현재 ContactListPage
위젯이 StatefulWidget
으로 구현되어 있고, builder
함수 내부에 FutureBuilder
에서 future: restClient.getContactList()
를 호출하고 있습니다. 이 경우 setState()
를 호출하면, builder
함수가 다시 실행되면서 getContactList()
API가 다시 호출 될 수 있으므로 주의가 필요합니다.
다른 방법으로는 MVVM 아키텍처를 적용하여 View에 있는 상태와 이벤트 로직을 ViewModel로 옮겨서 구현하는 방법이 있습니다.
View에서 화면을 그리는데 필요로하는 List<ContactItem>
을 ViewModel에 상태로 구현하고, 해당 데이터를 가져오는 getContactList()
이벤트 함수도 ViewModel에 구현하신 뒤, View의 initState()
함수에서 ViewModel의 getContactList()
함수를 호출하는 방식으로 구현하면 View에서 setState()
를 아무리 호출해도 통신은 1회만 하도록 만드실 수 있습니다.
보다 자세한 방법은 MVVM 섹션을 참고해 주세요.
Q2( ContactItem 15개를 ListView.builder 를 이용하여 출력하려고 하는데 어떻게 해야 되는지 몰라 도움 요청드립니다.
itemCount
로 전달한 값 만큼 itemBuilder
가 반복 실행되면서, index를 전달합니다.
해당 index를 이용하여 addrinfo[index]
로 값을 가져오시면 됩니다.
ListView.builder(
itemCount: addrinfo.length,
itemBuilder: (context, index) {
final item = addrinfo[index];
return Text('${item.userNM}');
},
);
보다 자세한 사용 방법은 공식 문서 및 블로그 예제를 참고해 주세요.
감사합니다 :)
답변 감사드립니다.
정말 많이 배우고 있습니다.
Card 로 표시하는 것은 나중에 세부 구현해보려고 합니다.
아래와 같이 구현하여 정상 동작되는 거 확인했습니다.