0

I am building a Dictionary app using using api owlbot. My code Run fines shows no error. But after the run time i am getting error ════════ Exception caught by widgets ═══════════════════════════════════════════ Null check operator used on a null value ════════════════════════════════════════════════════════════════════

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DictionaryPage(),
    );
  }
}

My Dictionary Page Code:

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart';
import 'package:flutter/material.dart';

class DictionaryPage extends StatefulWidget {
  @override
  _DictionaryPageState createState() => _DictionaryPageState();
}

class _DictionaryPageState extends State<DictionaryPage> {
  String url = "https://owlbot.info/api/v4/dictionary/";
  String token = "Your Key";

  TextEditingController textEditingController = TextEditingController();

  // Stream for loading the text as soon as it is typed
  late StreamController streamController;
  Stream? _stream;

  Timer? _debounce;

  // search function
  searchText() async {
    if (textEditingController.text.length == 0) {
      streamController.add(null);
      return;
    }
    streamController.add("waiting");
    Response response =
        await get(url + textEditingController.text.trim() as Uri,
            // do provide spacing after Token
            headers: {"Authorization": "Token " + token});
    streamController.add(json.decode(response.body));
  }

  @override
  void initState() {
    super.initState();
    streamController = StreamController();
    _stream = streamController.stream;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.black,
          title: Text(
            "Dictionary nw",
            style: TextStyle(color: Colors.white),
          ),
          centerTitle: true,
          bottom: PreferredSize(
            preferredSize: Size.fromHeight(45),
            child: Row(
              children: [
                Expanded(
                  child: Container(
                    margin: const EdgeInsets.only(left: 12, bottom: 11.0),
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(24.0),
                        color: Colors.white),
                    child: TextFormField(
                      onChanged: (String? text) {
                        if (_debounce!.isActive) _debounce?.cancel();
                        _debounce =
                            Timer(const Duration(milliseconds: 1000), () {
                          searchText();
                        });
                      },
                      controller: textEditingController,
                      decoration: InputDecoration(
                        hintText: "Search for a word",
                        contentPadding: const EdgeInsets.only(left: 24.0),

                        // removing the input border
                        border: InputBorder.none,
                      ),
                    ),
                  ),
                ),
                IconButton(
                  icon: Icon(
                    Icons.search,
                    color: Colors.white,
                  ),
                  onPressed: () {
                    searchText();
                  },
                )
              ],
            ),
          ),
        ),
        body: Container(
          margin: EdgeInsets.all(8),
          child: StreamBuilder(
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.data == null) {
                return Center(
                  child: Text("Enter a search word"),
                );
              }
              if (snapshot.data == "waiting") {
                return Center(
                  child: CircularProgressIndicator(),
                );
              }

              // output
              return ListView.builder(
                itemCount: snapshot.data["definitions"].length,
                itemBuilder: (BuildContext context, int index) {
                  return ListBody(
                    children: [
                      Container(
                        color: Colors.grey[300],
                        child: ListTile(
                          leading: snapshot.data["definitions"][index]
                                      ["image_url"] ==
                                  null
                              ? null
                              : CircleAvatar(
                                  backgroundImage: NetworkImage(snapshot
                                      .data["definitions"][index]["image_url"]),
                                ),
                          title: Text(textEditingController.text.trim() +
                              "(" +
                              snapshot.data["definitions"][index]["type"] +
                              ")"),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Text(
                            snapshot.data["definitions"][index]["definition"]),
                      )
                    ],
                  );
                },
              );
            },
            stream: _stream,
          ),
        ),
      ),
    );
  }
}

From my study I think this error occurred from ,

   if (_debounce!.isActive) _debounce?.cancel();
                        _debounce =
                            Timer(const Duration(milliseconds: 1000), () {
                          searchText();
                        });
                      },
                     

this, which i need to change according to this ,

Use a local variable

var f = foo;
if (f != null) {
  var len = f.length; // Safe 
}
Use ?. and ??

var len = foo?.length ?? 0; 
nvoigt
  • 75,013
  • 26
  • 93
  • 142

1 Answers1

0

You need to check if _debounce is already initialized (i.e. it's not null):

onChanged: (String? text) {
  // Use a local variable, as your snippet hints
  final Timer? debounce = _debounce;

  // Check if it's initialized AND if it's active
  if (debounce != null && debounce.isActive)
    debounce.cancel();

  // Initialize a new timer
  _debounce = Timer(const Duration(milliseconds: 1000), () {
    searchText();
  });
},
enzo
  • 9,861
  • 3
  • 15
  • 38
  • Just do: `debounce?.cancel();` . Nothing happens if you call `cancel()` on an inactive timer so no need for testing if it is active: https://api.dart.dev/stable/2.13.4/dart-async/Timer/cancel.html – julemand101 Aug 05 '21 at 16:59
  • In the case of "?." operator you can also omit assignment to local variable. – Alexander Farkas Aug 05 '21 at 17:08