inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

Flutter 앱 개발 실전

Riverpod 이론1

[문의] ListView.builder 처리

해결된 질문

278

Link

작성한 질문수 15

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 를 이용하여 출력하려고 하는데 어떻게 해야 되는지 몰라 도움 요청드립니다.

 

 

flutter

답변 1

1

DevStory

안녕하세요

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}');
  },
);

보다 자세한 사용 방법은 공식 문서블로그 예제를 참고해 주세요.

 

감사합니다 :)

2

Link

답변 감사드립니다.

정말 많이 배우고 있습니다.

Card 로 표시하는 것은 나중에 세부 구현해보려고 합니다.

아래와 같이 구현하여 정상 동작되는 거 확인했습니다.

class ContactResultPage extends StatefulWidget {
  const ContactResultPage({Key? key}) : super(key: key);

  @override
  State<ContactResultPage> createState() => _ContactListPageState();
}

class _ContactListPageState extends State<ContactResultPage> {
  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;

          if (ids.status.contains("success")) {
            final addrinfo = ids.addrinfo as List<ContactItem>;
            return _buildListView(context, addrinfo);
          } else {
            return const Center(
              child: Text('에러가 발생했습니다.'),
            );
          }
        },
      ),
    );
  }

  Widget _buildListView(BuildContext context, List<ContactItem> ids) {
    return ListView.builder(
      itemCount: ids.length,
      itemBuilder: (context, index) {
        final item = ids[index];
        return Column(
          children: [
            Text(item.idx.toString()),
            Text(item.userNM),
            Text(item.mobileNO),
            Text(item.photo ?? 'XXX'),
          ],
        );
      },
    );
  }
}

 

수강 기한 연장 요청드려도될까요..

1

48

2

37.provider 실습 문제점, 카트에서 상품이 지워지지 않습니다.

1

75

2

다트 프로젝트

1

51

2

context.read<LangService>().toggleLang 해도 언어가 변경되는 이유

1

74

3

수강 기간 연장 신청 요청드립니다.

1

68

3

수강기간 연장 부탁드립니다.

1

58

3

제공해주신 flutter_design_system 라이브러리 질문입니다.

1

53

2

수강 기간 연장 부탁드립니다

1

52

2

수강 기한 연장

1

78

3

강의 잘 보고있습니다!

1

59

2

애뮬레이터 실행 오류

1

69

2

pdf 강의노트

1

62

2

수강기간 연장 부탁드립니다.

1

86

2

수강 기간 연장 요청

1

86

2

수강기간 연장 부탁드립니다

1

129

2

코드 생성기 - build runner 관련 오류

1

110

1

디자인 시스템 구성에 대해 질문 드립니다

2

145

2

CartItem 추가시

1

95

2

const 커스텀클래스

1

95

1

강의 수강 기간 연장 요청드립니다.

1

127

2

코드 생성기 - 실습 build runner 안 되는 분.

1

270

2

Flutter 강의자료 열리지 않는 문제

1

165

2

riverpod 프로젝트에 궁금한점이 있어 질문 남깁니다.

1

123

2

수강 기강 연장 부탁드리겠습니다! :ㅇ

1

88

2