[Flutter] 주변 기기 스캔 목록 한번에 띄우기 (FutureBuilder)

김민서·2023년 8월 21일
0

가림 치료 앱 개발

목록 보기
2/6

FutureBuilder

FutureBuilder 공식 문서

사용자가 새로운 아이 패치를 추가하는 단계에서 주변 ble 기기들을 스캔할 때 이 위젯을 사용하게 되었다. ble 기기 스캔에는 flutter blue 라이브러리를 사용했는데, 이 때 timeout 설정을 통해 주변 기기를 4초 동안 스캔하도록 설정한 뒤 리스트(resultList)에 스캔 결과들을 차례대로 담았다. 아래는 ble 기기들을 스캔하는 함수이다.

Future<List<ScanResult>> scanPatch() async {
	setState(() {
    	_resultList.clear();
    });
    
    await flutterBlue.startScan(timeout: const Duration(seconds: 4));
    
    flutterBlut.scanResults.listen((results) {
		for (ScanResult r in results) {
        	if (!_resultList.contains(r)) {
				_resultList.add(r);
			}
        }
    });
    return _resultList;
}

이 함수가 실행되면 4초 동안의 스캔이 다 끝난 뒤 요소들이 담긴 리스트(_resultList)가 반환될텐데, 이 때 해당 리스트를 리스트뷰 형식으로 한 번에 화면에 띄워주고 싶었다. 여기서 FutureBuilder 위젯을 사용하여 이를 구현할 수 있었다. 이렇게!

FutureBuilder는 Future를 다루는 위젯이다. Future는 지금은 아직 사용할 수 없지만 미래에 있을 값을 나타내는 객체이다. 비동기 작업 처리에 사용된다.

그러면 FutureBuilder는 말 그대로 Future를 빌드하는 위젯인 것이다.
FutureBuilder로 Future의 현재 상태를 쉽게 파악하고, 데이터를 불러오는 동안 보여줄 것과 데이터가 다 불러와졌을 때 보여줄 것들을 따로 설정할 수 있다.

먼저 스캔 결과들이 담길 Future 객체를 선언한다.
(이 때 꼭 FutureBuilder 밖에서 선언해야 한다. FutureBuilder 안에서 선언할 경우 FutureBuilder의 상위 요소가 다시 구축될 때마다 데이터를 다시 가져오게 된다.)

late Future<List<ScanResult>> _scanPatch;

그리고 나의 경우, 스캔을 시작하는 textButton을 생성한 뒤 클릭할 때 기기 스캔 함수(scanPatch())가 실행되도록 해줬다.

FutureBuilder 는 다음과 같이 생성했다.
FutureBuilder 안의 future에 앞서 선언한 Future 객체인 _scanPatch 를 전달한다.
FutureBuilder의 snapshotconnectionState를 통해 Future의 상태를 확인하고 이에 맞는 적절한 화면을 보여준다.

  • 스캔이 완료되었으면 스캔 결과가 담은 리스트(_resultList)를 ListView 형식으로 보여준다.
  • 스캔 중이라면 로딩 아이콘을 보여준다.
FutureBuilder(
	future: _scanPatch,
    builder: (context, snapshot) {
    	if (snapshot.connectionState == ConnectionState.done) {
        	return Container(
            	ListView.spread(
                	itemBuilder: (BuildContext, index) {
                    	return ListTile(
                        	title: Text(_resultList[index].device.name)
                        );
                    }
                )
            );
        } else if (snapshot.connectionState == ConnectionState.waiting) {
			return LoadingIndicator();
        } else return Container();
    }
)

(위 코드는 실제 코드에서 css 요소들을 생략함)

0개의 댓글