0

I have a main.dart and has a button in center. When user tabs the button it navigate into home.dart page. My home.dart page also has a button on center and when user tabs the button it navigate to details page. The app tree and code is shown below.

I try to implement the "InheritedWidget" in my home.dart so after the home.dart as deep as I go I can call the "void _handleUserInteraction" function using "InheritedWidget". Unluckly I am keep getting error that says:

I/flutter (20715): The getter 'handleOnTap' was called on null.
I/flutter (20715): Receiver: null
I/flutter (20715): Tried calling: handleOnTap

home.dart code:

    import 'package:flutter/material.dart';
import 'dart:async';
import 'main.dart';
import 'details.dart';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Timer timer;

  // TODO: 1 - INIT STATE
  @override
  void initState() {
    super.initState();
    setState(() {
      _initializeTimer();
    });
  }

  // TODO: 3 - INITIALIZE TIMER
  void _initializeTimer() {
    timer = Timer.periodic(const Duration(minutes: 5), (__) {
      _logOutUser();
    });
  }

  // TODO: 4 - LOG OUT USER
  void _logOutUser() {
    timer.cancel();

    Navigator.push(
        context, new MaterialPageRoute(builder: (context) => new MyApp()));
  }

  // TODO: 5 - HANDLE USER INTERACTION
  // void _handleUserInteraction([_]) {
  void _handleUserInteraction() {
    print("+++++++ _handleUserInteraction Header ++++++++");
    if (!timer.isActive) {
      return;
    }
    timer.cancel();
    _initializeTimer();
    print("+++++++ _handleUserInteraction Footer ++++++++");
  }

  @override
  Widget build(BuildContext context) => MaterialApp(
        theme: ThemeData(
          primarySwatch: Colors.red,
        ),
        home: LoginState(
            callback: _handleUserInteraction,
            child: Builder(builder: homeScreenBuilder)),
      );
}

@override
Widget homeScreenBuilder(BuildContext context) {
  Function() _callback = LoginState.of(context).callback;
  return GestureDetector(
      onTap: _callback,
      onDoubleTap: _callback,
      onLongPress: _callback,
      onTapCancel: _callback,
      child: new Scaffold(
        appBar: AppBar(
          title: Text("HOME PAGE"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'GOTO DETAILS PAGE',
              ),
              new RaisedButton(
                  child: new Text("Details"),
                  onPressed: () {
                    Navigator.push(
                        context,
                        new MaterialPageRoute(
                            builder: (context) => new Details()));
                  })
            ],
          ),
        ),
      ));
}

class LoginState extends InheritedWidget {
  final Widget child;
  final Function() callback;
  final Key key;

  LoginState({@required this.callback, @required this.child, this.key})
      : super(key: key);

  @override
  bool updateShouldNotify(LoginState oldWidget) {
    return true;
  }

  static LoginState of(BuildContext context) =>
      context.inheritFromWidgetOfExactType(LoginState);
}

details.dart code:

import 'package:flutter/material.dart';
import 'home.dart';

class Details extends StatefulWidget {
  @override
  _DetailsState createState() => _DetailsState();
}

class _DetailsState extends State<Details> {
  @override
  Widget build(BuildContext context) {
    Function() _callback = LoginState.of(context).callback;
    return GestureDetector(
        onTap: _callback,
        onDoubleTap: _callback,
        onLongPress: _callback,
        onTapCancel: _callback,
        child: new Scaffold(
          appBar: AppBar(
            title: Text("Details PAGE"),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'Every time Tabed it reset the home timer',
                ),

              ],
            ),
          ),
        ));
  }
}

UPDATE: I change my home.dart code. The onTap: _callback is working but in details.dart I get same error saying that:

error: - The getter 'callback' was called on null.

Nick
  • 4,163
  • 13
  • 38
  • 63
  • Ok, I found it and its working now. Here is a link: https://github.com/flutter/flutter/issues/24673 – Nick Nov 26 '18 at 07:03
  • if you want to handle global user interaction. https://stackoverflow.com/questions/57666818/how-can-i-globally-handle-a-user-interaction – Naranmandakh Tsogoo Sep 06 '19 at 07:09

1 Answers1

0

The reason why you're getting the error The getter 'callback' was called on null. is because LoginState.of(context) is null.

class _DetailsState extends State<Details> {
  @override
  Widget build(BuildContext context) {
    Function() _callback = LoginState.of(context).callback;
    ...
  }
}

Since you're using InheritedWidget, I assume that you may be attempting to do state management. If so, you can check this guide on implementing app state management. One way of doing this is with the use of provider.

You can try running the sample below. I've based it from the given sample.

main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'dart:async';
import 'details.dart';

void main() {
  // https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifierprovider
  runApp(ChangeNotifierProvider(
    create: (context) => LoginState(),
    child: 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: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
    // This allows access to LoginState data if no UI changes needed
    // https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#providerof
    Provider.of<LoginState>(context, listen: false).initializeTimer();
  }

  @override
  Widget build(BuildContext context) {
    // Consumer grants access to LoginState
    // https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#consumer
    return Consumer<LoginState>(
      builder: (context, loginState, child) {
        return GestureDetector(
            onTap: () => loginState.handleUserInteraction(),
            // onDoubleTap: _callback,
            // onLongPress: _callback,
            // onTapCancel: _callback,
            child: new Scaffold(
          appBar: AppBar(
            title: Text("HOME PAGE"),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'GOTO DETAILS PAGE',
                ),
                new RaisedButton(
                    child: new Text("Details"),
                    onPressed: () {
                      Navigator.push(
                          context,
                          new MaterialPageRoute(
                              builder: (context) => new Details()));
                    })
              ],
            ),
          ),
        ));
      },
    );
  }
}

// https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifier
class LoginState extends ChangeNotifier {
  Timer _timer;

  void initializeTimer() {
    _timer = Timer.periodic(const Duration(minutes: 5), (__) {
      logOutUser();
    });
  }

  void logOutUser() {
    _timer.cancel();
  }

  void handleUserInteraction() {
    print("+++++++ _handleUserInteraction Header ++++++++");
    if (!_timer.isActive) {
      return;
    }
    _timer.cancel();
    initializeTimer();
    print("+++++++ _handleUserInteraction Footer ++++++++");
  }
}

details.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'main.dart';

class Details extends StatefulWidget {
  @override
  _DetailsState createState() => _DetailsState();
}

class _DetailsState extends State<Details> {
  @override
  Widget build(BuildContext context) {
    return Consumer<LoginState>(
      builder: (context, loginState, child) {
        return GestureDetector(
            onTap: () => loginState.handleUserInteraction(),
            // onDoubleTap: _callback,
            // onLongPress: _callback,
            // onTapCancel: _callback,
            child: new Scaffold(
          appBar: AppBar(
            title: Text("Details PAGE"),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'Every time Tabed it reset the home timer',
                ),
              ],
            ),
          ),
        ));
      },
    );
  }
}

Omatt
  • 8,564
  • 2
  • 42
  • 144