Иногда приложение Flutter вылетает после отправки данных

У меня проблема в моем приложении. Существует простая форма, в которой пользователь может отправлять текст и фотографии. Когда я отправляю данные, такие как текст и изображения, иногда мое приложение вылетает, оно показывает черный экран и зависает, но не всегда. Я не понимаю, в чем именно проблема. Вот мой исходный код:

    class WriteComplainWidget extends StatefulWidget {
      final GlobalKey<ScaffoldState> parentScaffoldKey;
      List<Asset> images = List<Asset>();

      RouteArgument routeArgument;
      final VoidCallback onPressed;

      Brand brand;
      WriteComplainWidget(
          {Key key,
          this.parentScaffoldKey,
          this.routeArgument,
          this.onPressed,
          this.brand})
          : super(key: key);
      Complaint complaint = new Complaint();

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

    class _WriteComplainWidgetState extends StateMVC<WriteComplainWidget> {
      GlobalKey<FormState> _complaintFormKey = new GlobalKey<FormState>();
      GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
      List<Asset> images = List<Asset>();
      File _video;
      String _error = 'No Error Dectected';
      bool isSubmitted = false;
      int counter = 0;
      VideoPlayerController _videoPlayerController;
      VideoPlayerController _cameraVideoPlayerController;
      TextEditingController brandNameController = new TextEditingController();
      @override
      void initState() {
        super.initState();
        ErrorWidget.builder = (FlutterErrorDetails details) => Container(
              decoration: BoxDecoration(color: Colors.white),
              alignment: Alignment.center,
              child: Center(
                child: Padding(
                  padding: const EdgeInsets.all(30.0),
                  child: Container(
                    height: 300,
                    width: 300,
                    child: Center(
                      child: Text(
                        S.current.an_error_has_occurred_please_restart_application,
                        style: Theme.of(context).textTheme.title,
                      ),
                    ),
                  ),
                ),
              ),
            );
      }

      @override
      Widget build(BuildContext context) {
        return isSubmitted == true
            ? CircularLoadingWidget(height: 500)
            : Scaffold(
                appBar: AppBar(
                  leading: new IconButton(
                    icon: new Icon(Icons.sort, color: Theme.of(context).hintColor),
                    onPressed: () =>
                        widget.parentScaffoldKey.currentState.openDrawer(),
                  ),
                  automaticallyImplyLeading: false,
                  backgroundColor: Colors.transparent,
                  elevation: 0,
                  centerTitle: true,
                  title: Text(
                    S.of(context).write_complaint,
                    style: Theme.of(context)
                        .textTheme
                        .title
                        .merge(TextStyle(letterSpacing: 0.1)),
                  ),
                  actions: <Widget>[
                    Stack(
                      children: <Widget>[
                        IconButton(
                            iconSize: 25,
                            icon: Icon(
                              Icons.notifications,
                              color: Color(0xFF5ea1c8),
                            ),
                            onPressed: () {
                              Navigator.push(
                                context,
                                MaterialPageRoute(
                                    builder: (context) => NotificationsWidget()),
                              );
                              setState(() {
                                counter = 0;
                              });
                            }),
                        counter != 0
                            ? new Positioned(
                                right: 11,
                                top: 11,
                                child: new Container(
                                  padding: EdgeInsets.all(2),
                                  decoration: new BoxDecoration(
                                    color: Colors.red,
                                    borderRadius: BorderRadius.circular(6),
                                  ),
                                  constraints: BoxConstraints(
                                    minWidth: 14,
                                    minHeight: 14,
                                  ),
                                  child: Text(
                                    '$counter',
                                    style: TextStyle(
                                      color: Colors.white,
                                      fontSize: 8,
                                    ),
                                    textAlign: TextAlign.center,
                                  ),
                                ),
                              )
                            : new Container()
                      ],
                    ),
                  ],
                ),
                body: SingleChildScrollView(
                  child: Center(
                    child: Form(
                      key: _complaintFormKey,
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.stretch,
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget>[
                          Padding(
                            padding:
                                const EdgeInsets.only(top: 20, left: 35, right: 35),
                            child: Container(
                              child: TypeAheadFormField(
                                onSaved: (input) =>
                                    widget.complaint.brandName = input,
                                validator: (input) => input.length < 1
                                    ? S.of(context).please_enter_brand_name
                                    : null,
                                noItemsFoundBuilder: (BuildContext context) => Text(
                                    S.current.not_found_no_such_brand,
                                    style: TextStyle(
                                        color: Theme.of(context).errorColor,
                                        fontSize: 18)),
                                textFieldConfiguration: TextFieldConfiguration(
                                  maxLength: 512,
                                  style: new TextStyle(color: Colors.black),
                                  controller: brandNameController,
                                  autofocus: false,
                                  decoration: InputDecoration(
                                    filled: true,
                                    fillColor: Colors.white,
                                    labelText: S.of(context).brand_name,
                                    labelStyle: TextStyle(
                                        color: Theme.of(context).focusColor),
                                    contentPadding: EdgeInsets.all(12),
                                    hintStyle: TextStyle(color: Colors.black),
                                    prefixIcon: Icon(Icons.business,
                                        color: Theme.of(context).accentColor),
                                    border: OutlineInputBorder(
                                        borderSide: BorderSide(
                                            color: Theme.of(context)
                                                .focusColor
                                                .withOpacity(0.2))),
                                    focusedBorder: OutlineInputBorder(
                                        borderSide: BorderSide(
                                            color: Theme.of(context)
                                                .focusColor
                                                .withOpacity(0.5))),
                                    enabledBorder: OutlineInputBorder(
                                        borderSide: BorderSide(
                                            color: Theme.of(context)
                                                .focusColor
                                                .withOpacity(0.3))),
                                  ),
                                ),
                                suggestionsCallback: (pattern) async {
                                  return BackendService.searchBrands(pattern);
                                },
                                itemBuilder: (context, suggestion) {
                                  return ListTile(
                                    title: Text(suggestion['name']),
                                  );
                                },
                                onSuggestionSelected: (suggestion) {
                                  widget.complaint.brandId =
                                      suggestion["id"].toString();
                                  brandNameController.text =
                                      suggestion["name"].toString();
                                },
                              ),
                            ),
                          ),

                          Padding(
                            padding: const EdgeInsets.only(left: 35, right: 35),
                            child: Container(
                              child: TextFormField(
                                onSaved: (input) => widget.complaint.body = input,
                                validator: (input) => input.length < 50
                                    ? S.of(context).please_describe_in_details
                                    : null,
                                keyboardType: TextInputType.text,
                                maxLines: 5,
                                maxLength: 2500,
                                autofocus: false,
                                style: new TextStyle(color: Colors.black),
                                decoration: InputDecoration(
                                  filled: true,
                                  fillColor: Colors.white,
                                  labelText: S.of(context).your_complaint,
                                  labelStyle: TextStyle(
                                      color: Theme.of(context).focusColor),
                                  contentPadding: EdgeInsets.all(12),
                                  hintStyle: TextStyle(
                                      color: Theme.of(context)
                                          .focusColor
                                          .withOpacity(0.7)),
                                  prefixIcon: Icon(Icons.insert_drive_file,
                                      color: Theme.of(context).accentColor),
                                  border: OutlineInputBorder(
                                      borderSide: BorderSide(
                                          color: Theme.of(context)
                                              .focusColor
                                              .withOpacity(0.2))),
                                  focusedBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                          color: Theme.of(context)
                                              .focusColor
                                              .withOpacity(0.5))),
                                  enabledBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                          color: Theme.of(context)
                                              .focusColor
                                              .withOpacity(0.3))),
                                ),
                              ),
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.only(left: 30.0, top: 10),
                            child: Wrap(
                              children: <Widget>[
                                SizedBox(
                                  height: 5,
                                ),
                                Row(
                                  mainAxisSize: MainAxisSize.min,
                                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                                  children: <Widget>[
                                    Column(
                                      children: <Widget>[
                                        ComplaintButton(
                                            color: Theme.of(context).accentColor,
                                            onPressed: loadAssets,
                                            icon: Icons.add_a_photo)
                                      ],
                                    ),
                                    Column(
                                      mainAxisSize: MainAxisSize.max,
                                      children: <Widget>[
                                        ComplaintButton(
                                          color: Theme.of(context).accentColor,
                                          icon: Icons.videocam,
                                          onPressed: () {
                                            _pickVideo();
                                          },
                                        ),
                                        if (_video != null)
                                          _videoPlayerController.value.initialized
                                              ? Expanded(
                                                  child: Stack(
                                                    children: <Widget>[
                                                      Container(
                                                        height: 100,
                                                        width: 100,
                                                        child: AspectRatio(
                                                          aspectRatio:
                                                              _videoPlayerController
                                                                  .value
                                                                  .aspectRatio,
                                                          child: VideoPlayer(
                                                              _videoPlayerController),
                                                        ),
                                                      ),
                                                      Positioned(
                                                        top: -15,
                                                        right: -15,
                                                        child: ClipRRect(
                                                          borderRadius:
                                                              BorderRadius.circular(
                                                                  16.0),
                                                          child: IconButton(
                                                            hoverColor: Colors.red,
                                                            icon: Icon(
                                                              Icons.delete,
                                                              color: Colors.red,
                                                              size: 23,
                                                            ),
                                                          ),
                                                        ),
                                                      ),
                                                    ],
                                                  ),
                                                )
                                              : Container()
                                        else
                                          Text(
                                            "Clic",
                                            style: TextStyle(fontSize: 18.0),
                                          ),
                                      ],
                                    ),
                                    SizedBox(width: 70),
                                    Expanded(
                                      child: Column(
                                        crossAxisAlignment: CrossAxisAlignment.end,
                                        children: <Widget>[
                                          buildGridView(),
                                        ],
                                      ),
                                    ),

                                  ],
                                ),
                              ],
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.only(
                                left: 80.0, right: 80, bottom: 30, top: 30),
                            child: BlockButtonWidget(
                              text: Text(
                                S.of(context).submit,
                                style: TextStyle(
                                    color: Theme.of(context).primaryColor),
                              ),
                              color: Theme.of(context).accentColor,
                              onPressed: _submit,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              );
      }


      void _removePicture(int index) {
        images.removeAt(index);
        setState(() {
          images = images;
        });
      }

      Widget buildGridView() {
        return images.length > 0
            ? Container(
                height: 50,
                width: 200,
                child: GridView.count(
                  mainAxisSpacing: 7.0,
                  crossAxisSpacing: 4.0,
                  crossAxisCount: 4,
                  children: List.generate(images.length, (index) {
                    Asset asset = images[index];
                    return Stack(
                      children: <Widget>[
                        AssetThumb(asset: asset, width: 150, height: 150),
                        Positioned(
                          top: -15,
                          right: -15,
                          child: ClipRRect(
                            borderRadius: BorderRadius.circular(16.0),
                            child: IconButton(
                              hoverColor: Colors.red,
                              icon: Icon(
                                Icons.delete,
                                color: Colors.red,
                                size: 23,
                              ),
                              onPressed: () => _removePicture(index),
                            ),
                          ),
                        ),
                      ],
                    );
                  }),
                ),
              )
            : Row();
      }


      Future<void> loadAssets() async {
        FocusScope.of(context).requestFocus(new FocusNode());
        List<Asset> resultList = List<Asset>();
        String error = 'No Error Dectected';

        try {
          resultList = await MultiImagePicker.pickImages(
            maxImages: 4,
            enableCamera: true,
            selectedAssets: images,
            cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
            materialOptions: MaterialOptions(
              actionBarColor: "#abcdef",
              actionBarTitle: "Example App",
              allViewTitle: "All Photos",
              useDetailsView: false,
              selectCircleStrokeColor: "#000000",
            ),
          );
        } on Exception catch (e) {
          error = e.toString();
        }

        if (!mounted) return;

        setState(() {
          images = resultList;
          _error = error;
        });
      }


      void _submit() async {
        if (_complaintFormKey.currentState.validate()) {
          _complaintFormKey.currentState.save();

          // string to uri
          Uri uri = Uri.parse('https://api.panaszoktest.com/v1/complaint/submit');
          developer.log(uri.toString() + DateTime.now().toString(),
              name: "uri-picture");
          // create multipart request
          http.MultipartRequest request = http.MultipartRequest("POST", uri);
          //
          setState(() {
            isSubmitted = true;
          });
          if (images.length > 0) {
            Flushbar(
              isDismissible: true,
              flushbarPosition: FlushbarPosition.TOP,
              message: S.of(context).please_wait,
              margin: EdgeInsets.all(8),
              borderRadius: 8,
              icon: Icon(
                Icons.info_outline,
                size: 28.0,
                color: Colors.blue[300],
              ),
              duration: Duration(seconds: 5),
              leftBarIndicatorColor: Colors.green[300],
            )..show(context);
            for (var i = 0; i < images.length; i++) {
              ByteData byteData = await images[i].getByteData();
              developer.log(images[i].name.toString() + DateTime.now().toString(),
                  name: "uri-picture");

              List<int> imageData = byteData.buffer.asUint8List();
              developer.log(
                  images[i].originalHeight.toString() + DateTime.now().toString(),
                  name: "uri-picture");

              http.MultipartFile multipartFile = http.MultipartFile.fromBytes(
                'photo' + i.toString(),
                imageData,
                filename: images[i].name,
                contentType: MediaType("image", "jpg"),
              );
              developer.log(images[i].name.toString() + DateTime.now().toString(),
                  name: "uri-picture");

              // add file to multipart
              request.files.add(multipartFile);

              developer
                  .log(request.files.add.toString() + DateTime.now().toString());
            }
          } else {}
          User _user = await getCurrentUser();
          request.fields["api_token"] = _user.apiToken;
          request.fields["subject"] = widget.complaint.subject;
          request.fields["body"] = widget.complaint.body;
          request.fields["brandName"] = widget.complaint.brandName;
          request.fields["brandId"] =
              widget.complaint.brandId != null ? widget.complaint.brandId : "";
          //request.fields["brandBranchName"] = widget.complaint.brandBranchName;
          request.fields["userId"] = _user.id.toString();
          request.fields["lang"] = "en";
          // send
          //var streamedResponse = await request.send();
          request.send().then((res) async {
            var response = await http.Response.fromStream(res);
            Map<String, dynamic> data = json.decode(response.body);
            if (data["data"] != null &&
                data["data"]["success"] != null &&
                data["data"]["success"] == true) {
              isSubmitted = false;
              Navigator.popAndPushNamed(context, "/Pages");
              Flushbar(
                isDismissible: true,
                flushbarPosition: FlushbarPosition.TOP,
                message: S.of(context).your_complaint_has_been_submitted,
                margin: EdgeInsets.all(8),
                borderRadius: 8,
                icon: Icon(
                  Icons.info_outline,
                  size: 28.0,
                  color: Colors.blue[300],
                ),
                duration: Duration(seconds: 3),
                leftBarIndicatorColor: Colors.green[300],
              )..show(context);
            } else if (data["data"] != null &&
                data["data"]["errorMessage"] != null) {
              setState(() {
                isSubmitted = false;
              });

              developer.log(data["data"]["errorMessage"],
                  name: "response-image-upload2");
              Flushbar(
                isDismissible: true,
                flushbarPosition: FlushbarPosition.TOP,
                message: S.of(context).failed,
                margin: EdgeInsets.all(8),
                borderRadius: 8,
                icon: Icon(
                  Icons.info_outline,
                  size: 28.0,
                  color: Colors.blue[300],
                ),
                duration: Duration(seconds: 5),
                leftBarIndicatorColor: Colors.red[300],
              )..show(context);
            }
          }).catchError((err) {
            print(err);
          });

        }
      }
}

----------------------------- здесь backend servcie --------------------------------------------------

class BackendService {
  static Future<List> searchBrands(
    String search,
  ) async {
    List brands = new List();
    User _user = await getCurrentUser();
    final String _apiToken = 'api_token=${_user.apiToken}';
    final String url =
        '${GlobalConfiguration().getString('api_base_url')}brand/search?$_apiToken&query=${search}';
    developer.log(url, name: "request-brand-search-url");
    final client = new http.Client();
    final streamedRest = await client.send(http.Request('get', Uri.parse(url)));
    var response = await http.Response.fromStream(streamedRest);
    developer.log(response.body, name: "brand search results");
    Map<String, dynamic> data = json.decode(response.body);

    for (var i = 0; i < data["data"].length; i++) {
      brands.add({
        "id": data["data"][i]["id"],
        "name": data["data"][i]["name"],
        "logoUrl": data["data"][i]["logoImage"][0]["url"]
      });
    }
    return brands;
  }
}

0 ответов

Другие вопросы по тегам