저번 포스팅에서 스토리지에 이미지 파일을 저장했습니다. 이번 포스팅에서는 스토리지에 저장된 이미지 파일을 불러오고, Firebase Storage에 대한 포스팅을 종료하려 합니다.
지난번에 하단에 GridView는 스토리지에 저장된 이미지 파일을 불러올 수 있도록 만든다고 했지요? 오늘 할일이 바로 그것입니다 ! 지난 포스팅에서 이미지를 저장하는 메소드를 생성했습니다 ! 우리가 이미지를 앱에서 직접 보기 위해서는 저장된 이미지 파일의 url을 생성해서 스토리지가 아닌, 데이터베이스에 따로 저장해야 합니다 ! 그리고 데이터베이스에서 url을 읽어와야 하는 것이죠 ! 이를 위해서는 우선, url을 얻어야 합니다. 하단에는 url을 얻을 수 있는 구문이 추가되었습니다.
Future<void> uploadImage() async {
final now = DateTime.now();
var ref = storage.ref().child('Images/$now.jpg');
ref.putFile(selectedImage!);
ref.getDownloadURL(); //이미지 파일의 url
}
이제, putFile과 동시에 데이터베이스에 url을 저장할 수 있도록 바꿔보겠습니다. 상단부에 새로운 상수를 정의합니다. Cloud Firestore를 사용하기 위해서입니다.
class _ImagePickerAppState extends State<ImagePickerApp> {
FirebaseStorage storage = FirebaseStorage.instance;
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance; // Cloud Firestore를 위한 상수
ImagePicker picker = ImagePicker();
File? selectedImage;
이제 메소드 내부에 Cloud Firestore에 url을 전송할 수 있도록 수정합니다.
...
Future<void> uploadImage() async {
final now = DateTime.now();
var ref = storage.ref().child('Images/$now.jpg');
var uploadTask = ref.putFile(selectedImage!);
final snapshot = await uploadTask.whenComplete(() => {});
final url = await snapshot.ref.getDownloadURL();
firebaseFirestore.collection('Images').doc().set({
'url': url,
});
}
...
일단, 잘 되는지 체크부터 하겠습니다. 기존의 전송했던 사진은 삭제하겠습니다.
잘 작동했다면, 새롭게 이미지가 등록되고, 데이터베이스에도 새로운 Images 컬렉션과 안에 url이라는 데이터항목이 생겼겠죠?
이미지는 잘 전송되었습니다.
데이터베이스에도 역시 잘 전송되었군요 ! 이 url을 통해서 이미지를 불러올 수 있겠습니다. 이미지를 불러올 수 있도록 gridView를 수정하겠습니다.
Widget _imageGallery() {
return StreamBuilder<QuerySnapshot>(
stream: firebaseFirestore.collection('Images').snapshots(),
builder: (context, snapshot) {
return (snapshot.connectionState == ConnectionState.waiting)
? const Center(
child: CircularProgressIndicator.adaptive(),
)
: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
crossAxisCount: 3),
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
final url = snapshot.data!.docs[index]['url'];
return Image.network(
url,
width: double.infinity,
fit: BoxFit.cover,
);
});
});
}
기존 코드보다 좀 더 복잡해졌죠? 일단, 데이터를 가져와야하기 때문에 StreamBuilder를 사용했습니다. stream값은 당연히, Images 컬렉션을 가져오는 stream값을 전달했고, url은 여러개의 문서가 있는 경우를 대비해서 index에 대한 url의 value를 가져오게끔 했습니다. 그리고, StreamBuilder이기 때문에 가져오는 시간에 차이가 존재하겠죠? 아직 데이터를 가져오지 못했다면, CircularProgressIndicator를 사용해서 부적절한 화면 랜더링 오류를 방지했습니다.
제대로 보이죠? 스토리지에 사진이 한장 더 있다구요? 그치만 그 사진은 url을 데이터베이스에 저장하지 못했기 때문에 불러올 수 없습니다.