How to use Functions of another File in Dart / Flutter?

113,696

Solution 1

You can write a file with just that function, like:

test.dart

void launchWebView () {
  print("1234");
}

and then import that file like this:

main.dart

import "test.dart";

class _MyHomePageState extends State<MyHomePage> {
   @override
   Widget build(BuildContext context) {
       launchWebView();

It is not really clean, but you can do that. Alternatively you can use a class with a static method like:

class test {
    static void foo() {
        print("1234");
    }
}

and then in your code invoke it like that (after the import):

test.foo();

Solution 2

Or you can just declare all your functions (helpers) inside a class and pass them as an argument to other class.

//The class which contains your functions
class HelperFunction{

  //Define your method
  void launchWebView () {
    print("1234");
  }

  //Pass that function to a class
  MyHomePage(launchWebView);

}

//The class which receives the function.
class MyHomePage extends StatefulWidget{
  //Retrieve the function and store it to a variable of type Function.
  final Function launchWebView;
  MyHomePage(this.launchWebView);
}

class _MyHomePageState extends State<MyHomePage> {
   @override
   Widget build(BuildContext context) {
     //Access that function in State class using widget keyword.
     widget.launchWebView();
   }
}  

Solution 3

Use mixin instead of global functions!

Why does this happen?

I'm using it over several different files and would love to create its own file and reference with the _launchwebview function anywhere in my app because there are several lines of code needed in order to make it work.

Underscored methods are private to a given library. Thus, if we define _launchwebview in one file, that function is in a mini-library (Source). So, the method will only be accessible within that file. I explored how to expose private methods across files, but found the solution messy. I thus think the question would be better answered using public functions. The problem is implementing a shared function within different classes rather than simply providing access.

I've chosen to add this solution for this particular question since the method (launching a web view) would be good to have implemented within every appropriate Widget class. Note that extension methods could also work in this case, but Flutter prefers composition over inheritance.

If we want to move a public, i.e. non-underscored method, to a different class without copy-pasting, we could try several outlined approaches. I have detailed the drawbacks of the existing options below.

Hacky solutions

  1. Using the part directive enables us to copy the source of one file with a private implementation and use it in another file. But this is discouraged because the technique increases the binary size, goes against the Effective Dart usage guide, and is clearly a code smell because we are copy-pasting the same code.
  2. Using global functions doesn't follow Object Oriented programming. Global state breaks the Encapsulation principle. OOP is the best paradigm to use within Dart apps because of the way the language is designed (classes). The top answer recommends global functions, however, this should be a last resort given the powerful language capabilities of Dart.
  3. Static functions break encapsulation and the Open-Closed principle. They are hard to integrate with state management solutions because we track the state within instance method contexts. For example, integrating provider and other packages like GetX.
  4. Defining a Function as a property of a class can lead to subtle bugs further down the line. For example, we could assign any function to this property because there is no function signature type checking. Furthermore, this is not a scalable solution with code duplications.

Solution: Mixins

Dart has inbuilt support for optionally adding functions to a class when we want to reduce duplicated code but avoid extending the whole class (Source). The mixin keyword enables this by mixing a class with some specific logic. We can restrict the mixin to a specific subclass with on if needed.

Code example

LaunchWebView.dart

mixin LaunchWebView on StatelessWidget { // you can also constrain the mixin to specific classes using on in this line.
  void launchWebView() {
    // Add web view logic here. We can add variables to the mixin itself as well.
  }
}

Usage

class ExampleClass extends StatelessWidget with LaunchWebView {
  Widget build(BuildContext context) {
    ....
  }

  void testFunction() {
    // We now have access to launchWebView().
    launchWebView();
  }
}

Solution 4

You can do that in different ways:

1. Global function:

Define your function in a file, say global.dart:

void func() => print('Hello');

To use it in any file, just call:

func();

2. Static function in a class:

Create a class, say Foo and define your function in it:

class Foo {
  static void func() => print('Hello');
}

To use it in any file, just call

Foo.func();

3. Use mixin:

  • If you want to use the function in any class:

    Create a mixin, say Bar:

    mixin Bar {
      void func() => print('Hello');
    }
    

    To use it in a class, just use with keyword followed by mixin.

    class Baz with Bar {
      void main() => func();
    }
    
  • If you want to restrict the mixin from being used with any class:

    class Foo {}
    

    Create a mixin, say Bar which is on Foo.

    mixin Bar on Foo {
      void func() => print('Hello');
    }
    

    To use Bar mixin we need to extend Foo class because this is what it is on.

    class Baz extends Foo with Bar {
      void main() => func();
    }
    
Share:
113,696
Charles Jr
Author by

Charles Jr

Jack of All Trades - Master of Few!! Started with Obj-C.then(Swift)!.now(Flutter/Dart)! Thank everyone for every answer, comment, edit, suggestion. Can't believe I've been able to answer a few myself :-)

Updated on December 24, 2021

Comments

  • Charles Jr
    Charles Jr over 2 years

    I have a Flutter app where I'm using the flutter_web_view package. I'm using it over several different files and would love to create its own file and simply reference with the _launchwebview function anywhere in my app because there are several lines of code needed in order to make it work. I know how to reference files and pass information but not methods/functions. Here is the class code...

    import 'package:flutter/material.dart';
    import 'package:flutter_web_view/flutter_web_view.dart';
    
    class ShopClass extends StatefulWidget {
      @override
      ShopClassState createState() => new ShopClassState();
    }
    
    class ShopClassState extends State<ShopClass> {
      String _redirectedToUrl;
      FlutterWebView flutterWebView = new FlutterWebView();
      bool _isLoading = false;
    
      @override
      initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        Widget leading;
        if (_isLoading) {
          leading = new CircularProgressIndicator();
        }
        var columnItems = <Widget>[
          new MaterialButton(
              onPressed: launchWebViewExample, child: new Text("Launch"))
        ];
        if (_redirectedToUrl != null) {
          columnItems.add(new Text("Redirected to $_redirectedToUrl"));
        }
        var app = new MaterialApp(
          home: new Scaffold(
            appBar: new AppBar(
              leading: leading,
            ),
            body: new Column(
              children: columnItems,
            ),
          ),
        );
        return app;
      }
    
    
      void launchWebViewExample() {
        if (flutterWebView.isLaunched) {
          return;
        }
    
        flutterWebView.launch("https://apptreesoftware.com",
            headers: {
              "X-SOME-HEADER": "MyCustomHeader",
            },
            javaScriptEnabled: false,
            toolbarActions: [
              new ToolbarAction("Dismiss", 1),
              new ToolbarAction("Reload", 2)
            ],
            barColor: Colors.green,
            tintColor: Colors.white);
        flutterWebView.onToolbarAction.listen((identifier) {
          switch (identifier) {
            case 1:
              flutterWebView.dismiss();
              break;
            case 2:
              reload();
              break;
          }
        });
        flutterWebView.listenForRedirect("mobile://test.com", true);
    
        flutterWebView.onWebViewDidStartLoading.listen((url) {
          setState(() => _isLoading = true);
        });
        flutterWebView.onWebViewDidLoad.listen((url) {
          setState(() => _isLoading = false);
        });
        flutterWebView.onRedirect.listen((url) {
          flutterWebView.dismiss();
          setState(() => _redirectedToUrl = url);
        });
      }
    
    
    
      void reload() {
        flutterWebView.load(
          "https://google.com",
          headers: {
            "X-SOME-HEADER": "MyCustomHeader",
          },
        );
      }
    }
    

    How can I use launchWebViewExample in another class?

  • Charles Jr
    Charles Jr about 6 years
    I successfully printed a statement, but I'm having a little trouble executing the launchWebView function in the class. Any ideas?
  • temirbek
    temirbek about 5 years
    how can you directly call method of other class without referencing that class?
  • Tomas Baran
    Tomas Baran almost 4 years
    I've been thinking btw these 2 options for quite some time. Could you please elaborate on pros/cons btw the two options. The first option doesn't sound like a rule-of-thumb option, right? Although, I don't know why. Could you explain why? On the other hand, I've read that it's best to avoid static methods/variables since they take up memory. But isn't the first option the same story in terms of memory though? In other words if I don't create a class just functions in a file isn't automatically each function static?
  • cofirazak
    cofirazak almost 3 years
    @Antonino Cacace you say top-level functions are not really clean in flutter. but why? Here is what they say in official docs: "Note: Consider using top-level functions, instead of static methods, for common or widely used utilities and functionality." dart.dev/guides/language/…
  • Pranav Kasetti
    Pranav Kasetti almost 3 years
    The Encapsulation principle is a core principle for good Object-Oriented design (OOP). The idea says that methods should be defined on object instances. Public methods are still called on objects, so they don't break the principle. I hope that helps.
  • Pranav Kasetti
    Pranav Kasetti almost 3 years
    It seems you don’t know what you’re talking about. I’m not talking about inheritance. Mixins are an example of composition.
  • Pranav Kasetti
    Pranav Kasetti almost 3 years
    How about you read what OOP is first? Then you wouldn't wonder why methods are better than top-level functions.
  • Pranav Kasetti
    Pranav Kasetti almost 3 years
    That's comparing static methods to top-level functions. I am talking about how instance methods are better than top-level functions. Let me know if you still have questions.
  • CopsOnRoad
    CopsOnRoad over 2 years
    In global functions part, you can also use import 'global.dart' as global in other file and then invoke the function using global.func();