Never give up

Flutter - Json serialize 본문

Flutter

Flutter - Json serialize

대기만성 개발자 2020. 10. 1. 13:23
반응형

구글 공식문서에 따르면 다음과 같은식으로 구현을 하는데

{
  "name": "John Smith",
  "email": "john@example.com"
}
//변환 할 json값

class User {
  final String name;
  final String email;

  User(this.name, this.email);

  User.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        email = json['email'];

  Map<String, dynamic> toJson() =>
    {
      'name': name,
      'email': email,
    };
}

 

여기서 조금 더 생각해야되는 부분이 있습니다

 

예제에 나온 serialize는 불러온 json 데이터가 하나일때는 처리할때는 이렇게 하지만

 

여러개일때는 어떻게 해야될지 고민이 됩니다

 

이전 예제처럼 처리하면 간단한데 (링크 참조 : devmemory.tistory.com/10)

 

해당 예제에서 사용했던 방식은 network에서 jsonData를 decoding해서

 

바로 List로 값을 옮기기 때문에 작동은 잘 되지만

 

값을 불러올때 key값이 혼동될수도 있고 소규모 프로젝트에는 적합하지만

 

대형 프로젝트에서는 적합하지 않다고 합니다

 

그래서 위에 구글에서 설명한 방식으로 여러 데이터가 있는 Json을 사용하면

 

Map이나 List형태를 마주치게될 수 있는데 여기에서는 List부분에 대해 다루겠습니다

 

Data

const String commentName = 'name';
const String commentEmail = 'email';
const String commentMessage = 'body';

class CommentData {
  final String name, email, message;

  CommentData({this.name, this.email, this.message});

  factory CommentData.fromJson(Map<String, dynamic> json) {
    return CommentData(
        name: json[commentName],
        email: json[commentEmail],
        message: json[commentMessage]);
  }
}

 

Network

class DataNetWork {
  final String url = 'https://jsonplaceholder.typicode.com/comments';

  Future getData() async {
    http.Response response = await http.get(url);

    if (response.statusCode == 200) {
      return response.body;
    } else {
      print(response.statusCode);
    }
  }

  List<CommentData> getCommentData(String response) {
    var data = jsonDecode(response).cast<Map<String, dynamic>>();

    return data
        .map<CommentData>((decodedData) => CommentData.fromJson(decodedData))
        .toList();
  }
}

 

Item

class CommentItem extends ChangeNotifier {
  List<CommentData> _list = [];

  UnmodifiableListView<CommentData> get getList => UnmodifiableListView(_list);

  int get getLength => _list.length;

  Future<void> setListData() async {
    DataNetWork netWork = DataNetWork();
    _list = netWork.getCommentData(await netWork.getData());
  }
}

 

Main

class CommentExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green,
      appBar: AppBar(
        title: Text('Comments'),
        backgroundColor: Color(0x00000000),
        elevation: 0,
      ),
      body: SafeArea(
          child: Container(
            padding: EdgeInsets.all(8),
              child: Consumer<CommentItem>(
                builder: (context, items, child) {
                  return ListView.builder(
                      itemCount: items.getLength,
                      itemBuilder: (context, index) {
                        var item = items.getList[index];
                        return Padding(
                          padding: const EdgeInsets.only(bottom: 4),
                          child: Card(
                              elevation: 8,
                              color: Colors.white,
                              child: ListTile(
                                leading: CircleAvatar(
                                  child: FlatButton(
                                    child: Text(item.name[0],
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            color: Colors.white, fontSize: 18)),
                                    onPressed: () =>
                                        Container(child: Text(item.name)),
                                  ),
                                ),
                                title: Text(item.email),
                                subtitle: Text(item.message),
                              )),
                        );
                      });
                },
              ))),
    );
  }
}

 

먼저 typo를 줄이기 위해 상수로 key값을 정의 해주고

 

data 클래스를 구글의 예제와 같은 폼으로 만들어줍니다

 

network 클래스에서 네트워크에서 값을 가져오는 부분은

 

비동기처리를 위해 future를 사용해주고 데이터를 가져올 때

 

decoding된 값을 cast<Map<>>처리를 해서 castList타입을 만들어줍니다

 

그리고 각각 List값들을 data class에 정의해놨던 fromJson을 통해

 

List<원하는 데이터 타입>형태로 만들어줍니다

 

그 후 원하는 대로 출력 하는식으로 했는데

 

구글 예제에 보면 이 부분은 백그라운드에서 처리하는 방법으로

 

compute(List<data>, json.body)를 사용합니다

(링크 : flutter-ko.dev/docs/cookbook/networking/background-parsing)

 

상황에 맞게 필요한 방법을 사용하면 될거 같습니다

 

ps. 스플래시 화면 혹은 해당 화면으로 넘어가기 전에 setListData를 콜 해줘야됩니다

 

 

여기까지는 구글 공식문서에 대한 설명을 토대로 만들어본 예제고

 

더 직관적인 코드로 해보자면 먼저 json값의 형태를 파악해야됩니다

 

그래서 decoded json값을 출력해보면 다음과 같이 나옵니다

I/flutter (20576): [{postId: 1, id: 1, name: id labore ex et quam laborum, email: Eliseo@gardner.biz, body: laudantium enim quasi est quidem magnam voluptate ipsam eos
I/flutter (20576): tempora quo necessitatibus
I/flutter (20576): dolor quam autem quasi
I/flutter (20576): reiciendis et nam sapiente accusantium}, {postId: 1, id: 2, name: quo vero reiciendis velit similique earum, email: Jayne_Kuhic@sydney.com, body: est natus enim nihil est dolore omnis voluptatem numquam
I/flutter (20576): et omnis occaecati quod ullam at
I/flutter (20576): voluptatem error expedita pariatur
I/flutter (20576): nihil sint nostrum voluptatem reiciendis et}, {postId: 1, id: 3, name: odio adipisci rerum aut animi, email: Nikita@garfield.biz, body: quia molestiae reprehenderit quasi aspernatur
I/flutter (20576): aut expedita occaecati aliquam eveniet laudantium
I/flutter (20576): omnis quibusdam delectus saepe quia accusamus maiores nam est
I/flutter (20576): cum et ducimus et vero voluptates excepturi deleniti ratione}, {postId: 1, id: 4, name: alias odio sit, email: Lew@alysha.tv, body: non et atque
I/flutter (20576): occaecati deserunt quas accusantium unde odit nobis qui voluptatem
I/flutter (20576): quia voluptas consequuntur itaque dolor
I/flutter (20576): et qui

[{key : value}]로 List<Map<String, dynamic>> 형태가 출력되는것을 확인할 수 있습니다

List<CommentData> getCommentData(String response) {
    List data = jsonDecode(response);

    List<CommentData> list = [];

    data.forEach((element) {
      list.add(CommentData.fromJson(element));
    });

    return list;
  }

그러면 response값을 List에 저장하고 반복문 안에서 list에 fromJson을 이용해서 add를 해줍니다

 

이렇게 처리해보니 조금 더 코드가 직관적으로 보이는거 같아서 필자는 후자를 선호합니다

 

반응형
Comments