์ด๋ฒ์์ ์ ๋ฒ ํฌ์คํ ์ ์ด์ด ํ์ด์ด๋ฒ ์ด์ค์ ์ปฌ๋ ์ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๊ณ ๋ฐ์ดํฐ๋ฅผ Flutterํ๋ก์ ํธ๋ก ๊ฐ์ ธ์ค๋ ์์ ์ ์งํํด ๋ณผ ๊ฒ์ด๋ค.
๋จผ์ Firebase ์ฝ์๋ก ์ด๋ํ๋ค.
์ฝ์ ์ข์ธก ๋ฉ๋ด์์ Firestore Database๋ฅผ ์ ํํ๋ค.
๊ทธ๋ฌ๋ฉด ์ด๋ ๊ฒ Cloud Firestore ์น์ ์ผ๋ก ์ด๋ํ๊ฒ ๋๊ณ ์ฌ๊ธฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ง๋ค๊ธฐ๋ผ๋ ๋ฒํผ์ ํด๋ฆญํ๋๋ก ํ๋ค.
์๋ก์ด ์ฐฝ์ด ๋จ๊ฒ ๋๋๋ฐ ์ฌ๊ธฐ์ ๋ณด์๊ท์น์ ์ ์ฉํ๋ผ๊ณ ํ๋ค.
๊ท์น์ ๋์ค์ ์ธ์ ๋ ์ง ์์ ์ด ๊ฐ๋ฅํ๋ฏ๋ก ์ง๊ธ์ 30์ผ ๋์๋ง ์ด์ด๋๋ ํ ์คํธ ๋ชจ๋๋ก ์๋์ ์ํค๋๋ก ํ๊ฒ ๋ค.
๋ค์์ผ๋ก ์ด๋ํ๋ฉด ํด๋น ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ ์ฅ๋๋ ์์น๋ฅผ ์ ํํ๋ผ๊ณ ๋ฌ๋ค ๊ธฐ๋ณธ์ผ๋ก ์ค์ ํด๋๊ณ ๋์ด๊ฐ๋๋ก ํ๊ฒ ๋ค.
์๋ฃ๊ฐ ๋๋ฉด ์ด๋ ๊ฒ ๋ฐ์ดํฐ ํ ์ด๋ธ ๊ฐ์ ํ๋ฉด์ด ๋์ค๊ฒ ๋๋ค. ์ฌ๊ธฐ์ ์ค์ํ ๊ฐ๋ ์ด ํ๋ ์๋๋ฐ
MySql์ด๋ MSSQL ๋ฑ์ RDBMS๋ผ๋ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์
Database > Table > Row ๊ทธ๋ฆฌ๊ณ ํ ์ด๋ธ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ค์์ํ๊ฒ ์ฌ๊ธฐ๋ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ค.
๊ทธ๋ฌ๋ Firestore๋ MongoDB์ ๊ฒฝ์ฐ ๋ฌธ์ํ ๋ฐ์ดํฐ ๋ฒ ์ด์ค๋ฅผ ๊ธฐ๋ณธ๊ตฌ์กฐ๋ก ํ๊ธฐ ๋๋ฌธ์
Database > Collection > Document > Collection > Document > ... ์ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ์ ์๋ค.
RDBMS์๋ ๋ค๋ฅด๊ฒ ๊ด๊ณ์ ๋ํ ์ ์ฝ์ฌํญ์ด ์๋ค ๋ณด๋ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ํ์ฅํ๋ ๊ฒ ๋งค์ฐ ํธ๋ฆฌํ๋ค๋ ์ฅ์ ์ด ์๋ค.
์ฐ๋ฆฌ๋ ์ฑํ ์ฑ์ ๊ตฌ์กฐ๋ฅผ ๋จผ์ ์ ํด๋ ๊ฒ์ธ๋ฐ
์ฑ์ ์ผ๋ฉด ์ฑํ ๋ฐฉ ๋ชฉ๋ก์ด ๋์ค๊ฒ ๋๊ณ ์ฑํ ๋ฐฉ ์์๋ ๋ฉ์์ง ๋ชฉ๋ก๊ณผ ์ฌ์ฉ์ ๋ชฉ๋ก์ด ์๋ ๋ชจ์ต์ผ๋ก ์ค๊ณํ ์์ ์ด๋ค.
์ค๊ณ๋ฅผ ํ ๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก '๋ชฉ๋ก'์๋ฅผ ๋ถ์ด๋ ๋ถ๋ถ์ '์ปฌ๋ ์ '์ด๋ผ ๋ถ๋ฅด๊ณ '๋จ์ผ ๊ฐ์ฒด'๋ '๋ํ๋จผํธ'๋ผ๊ณ ๋ถ๋ฅด๋๋ก ํ๊ฒ ๋ค.
์ฑํ ๋ฐฉ๋ชฉ๋ก(์ปฌ๋ ์ )์์๋ ์ฑํ ๋ฐฉ๊ฐ์ฒด(๋ํ๋จผํธ)๊ฐ ์กด์ฌํ๊ฒ ๋๊ณ
์ฑํ ๋ฐฉ๊ฐ์ฒด(๋ํ๋จผํธ)์์๋ ๋ฉ์์ง๋ชฉ๋ก(์ปฌ๋ ์ )๊ณผ ์ฌ์ฉ์๋ชฉ๋ก(์ปฌ๋ ์ )์ด ์กด์ฌํ๊ฒ ๋๊ณ
๋ฉ์์ง๋ชฉ๋ก(์ปฌ๋ ์ )์์๋ ๋ฉ์์ง๊ฐ์ฒด(๋ํ๋จผํธ)๊ฐ ์กด์ฌํ๊ฒ ๋๋ค
๋ฉ์์ง๊ฐ์ฒด(๋ํ๋จผํธ)์์๋ ๋ฉ์์ง ๋ด์ฉ์ด๋ ์๊ฐ ๋ฑ์ ๋ฃ์ผ๋ฉด ์ข๋ค.
๊ทธ๋ฌ๋ฉด ๋ฐ๋ก ๊ตฌ์กฐ๋ฅผ ์์ฑํด๋ณด๋๋ก ํ๊ฒ ๋ค.
๋นจ๊ฐ ๋๊ทธ๋ผ๋ฏธ ์์ ์ปฌ๋ ์ ์์์ ๋๋ฌ์ค๋ค
์ฑํ ๋ฐฉ ๋ชฉ๋ก(์ปฌ๋ ์ )์ ๋ง๋ค์ด ์ฃผ๋๋ก ํ๋ค.
์ฑํ ๋ฐฉ๋ชฉ๋ก(์ปฌ๋ ์ )์์ ์ฑํ ๋ฐฉ๊ฐ์ฒด(๋ํ๋จผํธ)๋ฅผ ๋ง๋ค์ด์ฃผ๋๋ก ํ ๊ป๋ฐ ๋ฌธ์ID๋ ์๋์ผ๋ก ๋ฐ๊ธ๋ฐ๋๋ก ํ๋ค.
๋ง์ฝ ์ฑํ ๋ฐฉ์ ์ด๋ฆ์ ์ ํด๋๊ณ ์ถ๋ค๋ฉด ์๋ ํ๋์ name์ ๋ฃ๊ณ ๊ฐ์๋ค๊ฐ ์ํ๋ ์ฑํ ๋ฐฉ ์ด๋ฆ์ ์จ๋ ๋ ๊ฒ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ์ ์ฅ์ ๋๋ฅธ๋ค.
์ด์ ์ฑํ ๋ฐฉ ํ ๊ฐ๊ฐ ๋ง๋ค์ด์ก์ผ๋ ๊ทธ ์์ ๋ฉ์์ง๋ชฉ๋ก(์ปฌ๋ ์ )์ ๋ง๋ค์ด์ฃผ๋๋ก ํ๋ค.
์ปฌ๋ ์ ์ ์ด๋ฆ์ messages๋ผ๊ณ ์ ํ๋ค
์ฑํ ๋ฐฉ์ ๋ง๋ค๋ฏ์ด ๋ฉ์์ง๊ฐ์ฒด(๋ํ๋ฉํธ)์๋ ์๋์์ด๋๋ฅผ ๋ถ์ฌํด์ฃผ๊ณ
์ด๋ฒ์๋ ๋ฉ์์ง ๊ฐ์ฒด์ ๋ด์ฉ์ด ๋ค๊ฒ ๊ฐ๊ฒ ๋๋ฏ๋ก content๋ผ๋ ํ๋๋ฅผ ์ถ๊ฐํ์ฌ ๋ด์ฉ์ ์ ๋ ฅํ์๋ค.
์ ์์ ์ผ๋ก ๋ฉ์์ง๊ฐ์ฒด(๋ํ๋จผํธ) ๋ํ ์ถ๊ฐ๊ฐ ๋์๊ณ ์ฑํ ๋ฐฉ์ ๋ฉ์์ง ํ ๊ฐ๋ ํ์ ํ๋ ์ํ๋ ๋งํผ ์ถ๊ฐํด๋ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ธฐ๋ณธ์ ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ๋ ๋์ด ๋ฌ์ผ๋ ์ด๋ฒ์ Flutter ํ๋ก์ ํธ๋ก ์ด๋ํ๋๋ก ํ๋ค.
์ ๋ฒ ํฌ์คํ ์์ ์์ฑํด๋๊ณ ํ์ด์ด๋ฒ ์ด์ค์ ์ฐ๋ํ ํ๋ก์ ํธ์์ ๋ ๊ฐ์ ํ์ผ์ ์ถ๊ฐํ๋๋ก ํ์.
๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ์ ๊ทธ๋ฆ์ด ๋ MessageModel ํด๋์ค๋ฅผ ์ดํด๋ณด๋๋ก ํ๊ฒ ๋ค.
message_model.dart
class MessageModel {
final String id; //ํด๋น ๋ํ๋จผํธ์ ID๋ฅผ ๋ด๊ธฐ์ํจ.
final String content;
MessageModel({
this.id = '',
this.content = ''});
//์๋ฒ๋ก๋ถํฐ mapํํ์ ์๋ฃ๋ฅผ MessageModelํํ์ ์๋ฃ๋ก ๋ณํํด์ฃผ๋ ์ญํ ์ ์ํํจ.
factory MessageModel.fromMap({required String id,required Map<String,dynamic> map}){
return MessageModel(
id: id,
content: map['content']??'',
);
}
Map<String,dynamic> toMap(){
Map<String,dynamic> data = {};
data['content']=content;
return data;
}
}
Model ํด๋์ค๋ ๋ฐ์ดํฐ์ ๊ทธ๋ฆ์ด๋ค. ์ฌ๊ธฐ์๋ ์๋ฒ๋ก๋ถํฐ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ๊ทธ๊ฒ์ ์ ๊ฐ๊ณตํด์
์ฑ์์ ์ฌ์ฉํ๊ธฐ ํธํ ํํ๋ก ๋ง๋ค์ด์ ธ์ผ ํ๋ค.
์ด๋ฒ์๋ MessageList๋ฅผ ํ์ํ ํ๋ฉด์ธ
MessageListScreenํด๋์ค๋ฅผ ์ดํด๋ณด๋๋ก ํ๊ฒ ๋ค.
message_list_screen.dart
import 'dart:developer';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test_chatapp/model/message_model.dart';
class MessageListScreen extends StatefulWidget {
const MessageListScreen({Key? key}) : super(key: key);
@override
State<MessageListScreen> createState() => _MessageListScreenState();
}
class _MessageListScreenState extends State<MessageListScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('๋ฉ์ธ์ง ๋ชฉ๋ก')),
body: StreamBuilder<List<MessageModel>>(
stream: streamMessages(), //์ค๊ณํ๊ณ ์ถ์ Stream์ ๋ฃ๋๋ค.
builder: (context,asyncSnapshot) {
if (!asyncSnapshot.hasData) { //๋ฐ์ดํฐ๊ฐ ์์ ๊ฒฝ์ฐ ๋ก๋ฉ์์ ฏ์ ํ์ํ๋ค.
return const Center(child: CircularProgressIndicator());
} else if (asyncSnapshot.hasError) {
return const Center(
child: Text('์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.'),
);
} else {
List<MessageModel> messages = asyncSnapshot.data!;//๋น๋๊ธฐ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ ๋ฆฌ์คํธ๋ทฐ ํ์
return Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(messages[index].content),
);
})),
],
);
}
},
),
);
}
Stream<List<MessageModel>> streamMessages(){
try{
//์ฐพ๊ณ ์ ํ๋ ์ปฌ๋ ์
์ ์ค๋
์ท(Stream)์ ๊ฐ์ ธ์จ๋ค.
final Stream<QuerySnapshot> snapshots = FirebaseFirestore.instance.collection('chatrooms/YLCoRBj59XRsDdav2YV1/messages').snapshots();
//์๋ญ ์ค๋
์ท(Stream)๋ด๋ถ์ ์๋ฃ๋ค์ List<MessageModel> ๋ก ๋ณํํ๊ธฐ ์ํด map์ ์ฌ์ฉํ๋๋ก ํ๋ค.
//์ฐธ๊ณ ๋ก List.map()๋ List ์์ element๋ค์ ์ํ๋ ํํ๋ก ๋ณํํ์ฌ ์๋ก์ด List๋ก ๋ฐํํ๋ค
return snapshots.map((querySnapshot){
List<MessageModel> messages = [];//querySnapshot์ message๋ก ์ฎ๊ธฐ๊ธฐ ์ํด List<MessageModel> ์ ์ธ
querySnapshot.docs.forEach((element) { //ํด๋น ์ปฌ๋ ์
์ ์กด์ฌํ๋ ๋ชจ๋ docs๋ฅผ ์ํํ๋ฉฐ messages ์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๋ค.
messages.add(
MessageModel.fromMap(
id:element.id,
map:element.data() as Map<String, dynamic>
)
);
});
return messages; //QuerySnapshot์์ List<MessageModel> ๋ก ๋ณ๊ฒฝ์ด ๋์ผ๋ ๋ฐํ
}); //Stream<QuerySnapshot> ์์ Stream<List<MessageModel>>๋ก ๋ณ๊ฒฝ๋์ด ๋ฐํ๋จ
}catch(ex){//์ค๋ฅ ๋ฐ์ ์ฒ๋ฆฌ
log('error)',error: ex.toString(),stackTrace: StackTrace.current);
return Stream.error(ex.toString());
}
}
}
์ฌ๊ธฐ์ ์ค์ํ ๋ถ๋ถ์ streamMessages๋ผ๋ ๋ฉ์๋ ์์ญ์ด๋ค.
์ฝ๊ฒ ๋งํด ๋ฐ์ดํฐ๋ฅผ ํ์ด์ด ๋ฒ ์ด์ค ๋ชจ๋๋ก๋ถํฐ Stream ํํ๋ก ์ ๊ณต๋ฐ๊ณ Stream ๋ด๋ถ์ ๋ฐ์ดํฐ๋ฅผ List <MessagesModel>๋ก ๊ฐ๊ณตํ์ฌ ๋ฐํํ๋ ์ญํ ์ ํด์ค๋ค.
์ฝ๋๋ ๋ชจ๋ ๊ฒ์ ์๋ ค์ฃผ๋ ์ ์ดํด๋ณด๋๋ก ํ์.
๋ง์ง๋ง์ผ๋ก main.dart์ ์์ค์ฝ๋๋ถํฐ ์ดํด๋ณด๋๋ก ํ๊ฒ ๋ค.
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_test_chatapp/screen/message_list_screen.dart';
import 'firebase_options.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MessageListScreen(),
);
}
}
์ฌ๊ธฐ์ ๋ณ ๋ด์ฉ ์์ด ์ ๋ฒ์ main()๋ฉ์๋ ์์์ Firebase๋ฅผ ์ด๊ธฐํํด์ฃผ๋๋ฐ ์ด์ด MessageListScreen()์ ํํ๋ฉด์ผ๋ก ์ ์ฉํด์ฃผ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ด์ ์ฑ์ ์คํํ๋๋ก ํ์.
์๊น DB์ ์ ๋ ฅํ๋ ๋ฐ์ดํฐ๊ฐ ์ ๋ฌ๋ค.
์ฌ๊ธฐ์ ๋ง์ฝ ์๋ฒ ์ธก ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊พผ๋ค๋ฉด
์ฑ์์๋ StreamBuilder๋ก ์ธํด ๋ฐ์ดํฐ์ ๋ณ๊ฒฝ์ ์๊ฒ ๋๊ณ
์ค์ค๋ก ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ํ๊ฒ ๋๋ค.
์ค๋ ํฌ์คํ ์ ์ฌ๊ธฐ๊น์ง ํ๋๋ก ํ๊ณ ๋ค์ ํฌ์คํ ์์๋ ๋ฉ์ธ์ง๋ฅผ ์ ๋ก๋ํ๊ณ ๊ทธ์ ๊ฑธ๋ง์ UI ๊ตฌ์ฑ์ ์งํํ๋๋ก ํ๊ฒ ๋ค.
'๐ Flutter' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Flutter] Linux์์ Flutter Web ํธ์คํ ํ๊ธฐ (1) | 2022.05.19 |
---|---|
[Flutter] Firebase๋ก ์ฑํ ์ฑ ๋ง๋ค๊ธฐ - 3 (๋ฐ์ดํฐ ์ ์ฅํ๊ธฐ) (0) | 2022.05.19 |
[Flutter] Firebase๋ก ์ฑํ ์ฑ ๋ง๋ค๊ธฐ - 1 (ํ์ด์ด๋ฒ ์ด์ค ์ฐ๋ 3.0.0) (0) | 2022.05.18 |
[Flutter] Windows ๋น๋์ Bad UTF-8 encoding ์ค๋ฅ ๋ฐ์ ํด๊ฒฐ ๋ฐฉ๋ฒ (0) | 2022.05.17 |
[Flutter] QR์ฝ๋ ์ธ์ํ๊ธฐ (0) | 2022.05.13 |