티스토리 뷰

Flutter

flutter combobox 어렵네...

바람사탕 2022. 8. 26. 23:59
반응형

flutter combobox 홈페이가서,
소스코드 그대로 넣었더니, 안됨.
이것만 그런게 아니라, 다른것도 많이 안됨.

이래서 개발이 어려움.
그깟 콤보박스 하나 쓰는데, 뭐가 이리 어렵게 해놓았는지...


다른소스도 안됨...
유튜브에 된다고 올려놓은것도 안됨.(원래 Flutter가 자주 바뀐다고 함...)

안된다고 질문도 올라옴.




다른것도 에러...

Failed assertion: line 890 pos 15: 'items == null || items.isEmpty || value == null ||
              items.where((DropdownMenuItem<T> item) {
                return item.value == value;
              }).length == 1'




되는 샘플코드 발견
DropdownButton class - material library - Dart API (flutter.dev)

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(title: const Text(_title)),
        body: const Center(
          child: MyStatefulWidget(),
        ),
      ),
    );
  }
}

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

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  String dropdownValue = 'One';

  @override
  Widget build(BuildContext context) {
    return DropdownButton<String>(
      value: dropdownValue,
      icon: const Icon(Icons.arrow_downward),
      elevation: 16,
      style: const TextStyle(color: Colors.deepPurple),
      underline: Container(
        height: 2,
        color: Colors.deepPurpleAccent,
      ),
      onChanged: (String? newValue) {
        setState(() {
          dropdownValue = newValue!;
        });
      },
      items: <String>['One', 'Two', 'Free', 'Four']
          .map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value),
        );
      }).toList(),
    );
  }
}

그런데, 이건...리스트박스이지, 콤보박스가 아니다...


Dart언어는 참 ㅈㄹ같이 만들어 놓았다.
콤보박스 하나 쓰는데, 이렇게 어려운가?

Fulterr로 개발하다보니, 참 이상한게 한두가지가 아니다.

누가 이렇게 만들어 놯는지...
(다른 사람들은 불평 없이(?) 잘쓰니...아무 문제 없나 보지...)

이렇게된 이유는 주로 서로다른 초~중급 개발자들이 하나의 뭔가를 만들때 나타난다.
예를 들면, 자바언어를 정확히 아는 사람이 거의 없다. 대충 돌아가게만 써본 중급자들만 있다.
비슷한 파이썬 개발자와 같이 "x언어"를 개발했다고 치자.
자바의 장점과 파이썬의 장점을 살려서 "x언어"를 만들었다.
이 언어는 2개의 장점만 넣었기때문에 좋아야 한다.
그런데, 자바도 아니고, 파이썬도 아닌것이 만들어졌다.
이 상황에서 알기 어려운 버그가 발생했다.
그 누구도 왜 발생하는지 모른다.
몇년 후 새로 들어온 개발자가, 업그레이드를 한다.
버그는 안나게 돌려막기를 한다.
그러다 보니 점점 무거워진다.
이런 경우는 생각보다 많다.
C#도 이런 예중에 하나이다.
"왜 그렇게 해야하는지, 정확하게 아는사람이 없다."
"과연 이 코드가 효율적으로 잘 동작하는가?" 신경쓰는 사람도 없다. 돌아가니깐...


Flutter(Dart)개발자는 왜 Future를 좋아할까?

"Future", "비동기"문제는 Flutter(Dart)만의 문제는 아니다.
C# 같은 경우에도 "콜백지옥"이라는 말을 쓰기도 한다.

비동기로 처리할 수 있는 방법은 여러가지이다.
그중에 몇가지가 이벤트, 콜백, 인터럽트, 등등이 있다.
방법은 한가지가 아니다.

Flutter(Dart)는 'Future'키워드를 제공하여, 언어 자체에서 비동기 처리를 지원한다.
(이벤트 방식이라고 봐도 될듯....내부적으로 어떻게 처리되는지는 모르겠다.)

암튼 문제를 해결하기위해 "Future"를 도입했는데,
문제는 잘 해결되었지만, 부가적인 문제가 또 발생한다.
그중에 몇가지는 아래와 같다.
- 어렵다.
- 버그 발생 소지가 높다.

그런데, 과연 "이 방식이 효과적인가?"라는 의문을 하지 않을 수 없다.
잘 동작하니깐 쓰겠지...

이건 마치 C#이 콜백으로 문제점을 해결하려고 했는데, "콜백 지옥"이 만들어진것과 매우 유사하다.
"꼭 이런식으로 해결해야만 했나?"


인터넷 블로그에 아래와 같은 설명이 있다.

동기적으로 처리했을 경우 
Future<int> 에서 값이 나올 때까지 100줄의 코드는 동작하지 않고
정지해 있을 것이다. (심한 낭비)

이러한 낭비를 막고자 비동기적 으로 처리하는 것이다. 
(Future<int> 에서 값이 나오지 않아도 계속해서 동작을 수행할 수 있도록)

100줄이 동작하지 않고 멈추어 있다는것은 "심한 낭비"가 아닐 수 도 있다.
어차피, 대기하고 있을땐, 다른거 못할 가능성이 크다.
그리고, 대기중에는 Cpu_Sleep과 비슷한 명령을 사용하면 소비전력도 줄어든다.(물론 이렇게 사용하지는 않고 있다)
대기를 "알차게" 사용하는 방법도 있다는 말이다.
언제 나올지도 모르는것을 가지고 계속 코드를 실행해 나가야 한다.
어차피 Future도 콜백으로 구현되어 있을 가능성이 크다. 아니면, 눈으로 보이지 않지만, 아마도, 내부적으로 무수히 많은 비교문이 호출될 것으로 보여진다. "Future 완료 되었나?"

과연 어느것이 더 효율적이라고 말할 수 있는가?




flutter로 개발하면, 애플 iOS까지 되어서 좋긴한데, 기본으로 약 10Mbyte이상의 실행파일 크기를 가진다.
그리고, 좀 느리다.




다른 콤보박스 소스 해보니...역시나 안됨... 뭔 에러가 이렇게 많은지...

Error: Cannot run with sound null safety, because the following dependencies
don't support null safety:


.dart:119:25: Error: No named parameter with the name 'autovalidate'.
                        autovalidate: true,
                        ^^^^^^^^^^^^


좋게 만들자고 넣은 것들이 전부 장애물이 되고 있음....물론 나만 그런거겠지...
개발 참 드럽게 힘드네....


화면 꺼짐 5분으로 했는데, 자꾸 잠겨버리네....잠금화면 해제해야함. 핸드폰까지 속썩임...


아주 간단한 에러도 나오네...

don't support null safety:

 - package:dropdownfield
flutter run --no-sound-null-safety

사람들이 이렇게 하란다. (도대체 null safety는 왜 넣은거야?)
이 방법도 문제에 문제에 문제....꼬리에 꼬리를 무는 문제...
설정 변경도 어렵네...

한달전에 끝났어야 하는 문제가, 아직도 골치아프네...
좀 쉬어야겠다...


개발 쉽지 않음....




다른 샘플코드...역시 에러투성이... 되는게 없냐?

import 'package:dropdownfield/dropdownfield.dart';
import 'package:flutter/material.dart';
import 'dart:async';

void main() async {
  runApp(MaterialApp(title: 'MyApp', home: ExampleForm()));
}

class ExampleForm extends StatefulWidget {
  ExampleForm();

  @override
  _ExampleFormState createState() => _ExampleFormState();
}

class _ExampleFormState extends State<ExampleForm> {
  // Create a global key that will uniquely identify the Form widget and allow
  // us to validate the form
  final _formKey = GlobalKey<FormState>();
  Map<String, dynamic> formData;
  List<String> cities = [
    'Bangalore',
    'Chennai',
    'New York',
    'Mumbai',
    'Delhi',
    'Tokyo',
  ];
  List<String> countries = [
    'INDIA',
    'USA',
    'JAPAN',
  ];

  _ExampleFormState() {
    formData = {
      'City': 'Bangalore',
      'Country': 'INDIA',
    };
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: buildFutures(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          switch (snapshot.connectionState) {
            default:
              if (snapshot.hasError) {
                return Text(snapshot.error.toString());
              } else {
                if (snapshot.data != null)
                  return Scaffold(
                      appBar: AppBar(
                        titleSpacing: 5.0,
                        title: Text(
                          'Custom Dropdown Field Example',
                          style: TextStyle(fontSize: 15.0),
                        ),
                        actions: <Widget>[
                          Builder(
                            builder: (BuildContext context) {
                              return IconButton(
                                  icon: const Icon(Icons.check),
                                  iconSize: 20.0,
                                  tooltip: 'Save',
                                  onPressed: () async {
                                    if (_formKey.currentState.validate()) {
                                      _formKey.currentState.save();
                                      _formKey.currentState.save();
                                      showDialog<String>(
                                          context: context,
                                          builder:
                                              (BuildContext dialogContext) =>
                                                  AlertDialog(
                                                    content: Text(
                                                        'Data submitted is \n${formData.toString()}'),
                                                  ));
                                    }
                                  });
                            },
                          )
                        ],
                      ),
                      body: Container(
                        color: Colors.white,
                        constraints: BoxConstraints.expand(),
                        child: Form(
                            key: _formKey,
                            autovalidate: false,
                            child: SingleChildScrollView(
                                child: Column(
                              children: <Widget>[
                                Divider(
                                    height: 10.0,
                                    color: Theme.of(context).primaryColor),
                                DropDownField(
                                    value: formData['City'],
                                    icon: Icon(Icons.location_city),
                                    required: true,
                                    hintText: 'Choose a city',
                                    labelText: 'City *',
                                    items: cities,
                                    strict: false,
                                    setter: (dynamic newValue) {
                                      formData['City'] = newValue;
                                    }),
                                Divider(
                                    height: 10.0,
                                    color: Theme.of(context).primaryColor),
                                DropDownField(
                                    value: formData['Country'],
                                    icon: Icon(Icons.map),
                                    required: false,
                                    hintText: 'Choose a country',
                                    labelText: 'Country',
                                    items: countries,
                                    setter: (dynamic newValue) {
                                      formData['Country'] = newValue;
                                    }),
                              ],
                            ))),
                      ));
                else
                  return LinearProgressIndicator();
              }
          }
        });
  }

  Future<bool> buildFutures() async {
    return true;
  }
}
반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함