Dart Mixins Tutorial for Flutter : Getting Started

[ad_1]

Object Oriented Programming plays a major role in the software development process. Many design patterns use the OOPs concept, so it’s important to know how to use different methods to make your application more scalable and debug easily. If you come from a tech background, you might have heard about inheritance, abstraction and other pillars of OOPs. Mixins help you implement some of these pillars.
In this section, you’ll learn about:

  • Mixins
  • How they’re different from inheritance

In the first section of this article, you’ll start by downloading the projects and required versions of Flutter and Android Studio. It’s time to start.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.

Open the starter project in VS Code or Android Studio. This tutorial uses VS Code, so you might need to change some instructions if you decide to go with Android Studio.

After opening the project, run Flutter Pub Get in the terminal, to install the packages this project uses.

Exploring the Starter Project

Build and run the starter project. You’ll observe the following screen:
Starting screen of animation

  • When you build and run the project, the following screen will appear. It has two buttons.
  • If you click either of these two buttons, nothing happens. Rather, if you open start_screen.dart, you find two TODOs where you’ll connect these screens.
  • In first_animation.dart and second_animation.dart file, the animations are already in place. The task is to create a common code base which you’ll implement using mixins.

Now, you’re all set to learn about mixins and start implementing your first mixin class.

Setting up the Foundation for Mixins

Before learning about mixins in Flutter, you first have to go quickly through the basics of OOPs. You’ll learn about inheritance and composition in the following section.

Recalling Inheritance and Composition

Definition of inheritance: Inheritance means inheriting/using the methods and functions of the parent class in the child class.

Definition of composition: Composition is the relation between different classes where the classes need not be the parent and child class. It represents a has a relation. The composition represents a strong relationship. It means if class A has Class B, then Class B can’t exist without class A.

How inheritance differs from composition: Inheritance defines the is a relationship where the child class is a type of parent class. Composition defines a part of relationship where the child is a part of the parent. Here’s an example:

Car is an automobile; it’s an example of inheritance.
Heart is part of human; it’s an example of composition.

Inheritance offers strong coupling, making it difficult to change or add functionality in the parent classes, whereas composition offers loose coupling. You might wonder why you would still use inheritance when you can use composition. The answer is that both have benefits and use cases, like how different fishing rods have their use cases.

Multiple inheritances in Flutter: Flutter doesn’t support multiple inheritances like some programming languages, such as C++. But there are ways to get the functionality of multiple inheritances in Flutter, which you’ll learn in the following sections.

Now, you have an image of the differences between inheritance and composition. In the next section, you’ll learn about mixins.

Getting Into Mixins

What Are Mixins?

Mixins are a language concept that allows to inject some code into a class. In Mixin programming, units of functionality are created in a class and then mixed in with other classes. A mixin class acts as the parent class (but is not a parent class), containing the desired functionality.

The following mixin code snippet will help you understand this better:

Without using Mixin Class:

class WithoutMixinClass{
	void run(){
		print("Hey, without mixin class's method running!!");
	}
}

class OtherClass extends WithoutMixinClass{

}

void main(){
	OtherClass obj=OtherClass();
	obj.run();
}

In the snippet above, you inherit WithoutMixinClass, which is inherited in OtherClass using the extends keyword. So the OtherClass is the child class of WithoutMixinClass.

Using Mixin Class:

mixin MixinClass{
	void run(){
		print("Hey, mixin class's method is running!!");
	}
}

class OtherClass with MixinClass{}

void main(){
	OtherClass otherClassObj=OtherClass();
	otherClassObj.run();
}

In the snippet above, you use MixinClass in OtherClass using the with keyword. The OtherClass isn’t the child class. You need to use the with keyword to implement mixins.

Are you getting confused between the with, implements and extends keywords available in Dart? No worries. The following section will clarify your understanding.

With, Implements and Extends

If you have some basic experience with Flutter, you might have already used implements and extends. In this section, you’ll learn the differences between with, implements and extends.

Extends keyword:

  • Used to connect abstract parent classes with child classes.
  • Methods of abstract classes need not be overridden in child classes. This means if there are 10 methods in the abstract class, the child class need not have to override all 10 methods.
  • Only one class can be extended by a child class (Dart does not allow multiple inheritance)

Implements keyword:

  • Used to connect interface parent classes with other classes. Because Dart does not have any interface keyword, the classes are used to create interfaces.
  • Methods for interface classes need to be overridden in child classes. This means if there are 10 methods in the interface, the child class needs to override all 10 methods.
  • Multiple interface classes can be implemented.

With keyword:

  • Used to associate mixin classes with other classes.
  • Every method of the mixin class is imported to the other class.
  • Multiple mixin classes can be used with the same class.

With the basics clear, you’re ready to implement the first mixin class in the Flutter project. You’ll learn about this in the next section.

Implementing Your First Mixin Class

At this stage, you have enough knowledge to start implementing your first mixin class. If you have gone through the project structure, open base_screen.dart. Copy and paste the following code snippet in place of //1.TODO: create mixin class.

//1
mixin BasicPage<Page extends BaseScreen> on BaseState<Page> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: fab(),
        appBar: AppBar(
          title: Text(screenName()),
        ),
        body: Container(
          child: body(),
          color: Colors.black,
        ));
  }

  //2
  Widget fab();

  Widget body();
}

Here’s how this code works.

  1. To declare mixins in Flutter, you need to use the mixin keyword. BasicPage is the name of mixin, which has an object type of Page that extends the BaseScreen abstract class.
  2. Here, you declare functions that, if needed, you’ll implement in the child classes.

This just set up your custom mixin class. The project application requires multiple mixins because you’ll also use SingleTickerProviderStateMixin, which creates tickers in Flutter.

Note: Ticker can be called as a special period timer which notifies when Flutter Engine is about to draw a new frame. You can read the offical documents about Ticker here: Ticker Class.

In the next section, you’ll connect mixins and observe them working.

Integrating Multiple Mixins

In the previous section, you created a custom mixin that will act as base screens for other screens of the applications. In this section, you’ll connect screens and use mixins to create the required output.

Open first_animation.dart file and replace //1. TODO: declare here with the following line:

with BasicPage, SingleTickerProviderStateMixin

To use multiple mixins in Flutter, you need to use commas to separate mixins.

Replace the //2. TODO: Initialize controller here with the following code:

controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 10))
          ..addListener(() {
            setState(() {});
          });

Here, you initialize the animation controller. The this keyword used here is provided by SingleTickerProviderStateMixin, which provides the current context to the animation controller. Vsync keeps track of the application screen and only starts animation when the screen is displayed.

In the same file, search for //3.TODO: remove build method and remove the build code block. Because you have extended the class with the BasicPage class, the body method will be overridden and the body method present in the first_animation.dart will be used.

Now, you need to connect first_animation.dart with the start_screen. To do this, find and replace //1. TODO: Add here in start_screen.dart with the following code block:

Navigator.of(context).push<void>(
  MaterialPageRoute(
      builder: (context) => const FirstAnimationScreen()),
);

This is Navigator, which will push the FirstAnimationScreen to the UI stack. Import first_animation.dart into start_screen.dart for the code above to work.

Build and run the app. You’ll see the following output:
First part of animation mixin

You have created a mixin custom class and connected it with the application.

The next part of this section is a test for you. You’ll use the things learned in this section and complete a task.

Testing Your Knowledge

This section is a small test for you based on the things you learned in the previous sections. You need to complete the second_animation.dart file. The TODOs have been marked in the files for your ease.

If you run into difficulty, you can refer to the Test Solution given below or go through the final folder in the attached project material.

Test Solution
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'base_screen.dart';

class SecondAnimation extends BaseScreen {
  const SecondAnimation({Key? key}) : super(key: key);
  @override
  _SecondAnimationState createState() => _SecondAnimationState();
}

class _SecondAnimationState extends BaseState<SecondAnimation>
    with BasicPage, SingleTickerProviderStateMixin {
  Duration duration = Duration.zero;
  late Ticker ticker;

  @override
  void initState() {
    super.initState();
    ticker = this.createTicker((elapsed) {
      setState(() => duration = elapsed);
    });
  }

  @override
  void dispose() {
    ticker.dispose();
    super.dispose();
  }

  @override
  String screenName() => 'Timer screen';

  @override
  Widget fab() {
    return FloatingActionButton.extended(
      onPressed: () {
        if (!ticker.isActive) {
          ticker.start();
        } else {
          ticker.stop();
        }
      },
      label: Text((!ticker.isActive) ? 'Start Timer' : 'Stop Timer'),
      icon: Icon(
          (!ticker.isActive) ? Icons.timer_outlined : Icons.timer_off_outlined,
          color: Colors.white),
    );
  }

  @override
  Widget body() {
    return Center(
      child: Text(
        duration.inSeconds.toString(),
        style: TextStyle(
          fontSize: 220,
          color: Theme.of(context).colorScheme.primary,
        ),
      ),
    );
  }
}

Build and run the app. You’ll see the following screen:
Final part of animation

Great job! It’s important to test your newly learned skills to see whether you’re acquiring the knowledge. If you missed something, you can go back to previous sections and check what’s missing. Here’s a star badge for you:
Star badge

In the next section, you’ll learn about the role of hierarchy in mixins.

Understanding the Role of Hierarchy

An interesting thing about using multiple mixins is that the order they’re returned determines the method calling order. Here’s an example:

class A extends B with C, D{}

Hierarchy in mixins

In the class declaration above, the order they’re declared is from left to right. This can be understood by thinking of the calling data structure as a stack.

Now, look over to your project.

If you look at the first_animation.dart file, you see the following code:
extends BaseState with BasicPage, SingleTickerProviderStateMixin

According to this line, the hierarchy stack looks something like this:

Mixins in the project

This implies that if you move from left to right, the declared classes get inserted into the stack and the importance level increases. So in any function/method with the same name described in both SingleTickerProviderStateMixin and BasicPage, the one in the SingleTickerProviderStateMixin will be executed.

You now understand what mixins are in Dart, how they’re used and how they work. Next, you’ll learn why to use mixins.

Why Use Mixins?

Now that you’ve learned about mixins, it’s important to know why one would use them. Are there benefits of using mixins over other techniques, such as inheritance?

Don’t Repeat Principle: If your project uses the same code multiple times, it’s recommended to use a single code and extend it to your required classes. This also means code reusing. The use of mixins enhances code reusability.

Diamond Problem in OOPs: Using multiple inheritances often leads to the diamond problem. Mixins are not a way of using multiple inheritances in Dart; rather, they’re a way of reusing code from multiple hierarchies without using the extend keyword. When you use mixins, the mixins class is not parallel but is at the top of the class using it. Thus, the methods don’t conflict with each other and prevent the diamond problem.

The diamond problem is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a method in A that B and C have overridden, and D does not override it, then which version of the method does D inherit: that of B, or that of C?

Playing Safe With Mixins

You’ve gone through the introduction to mixins and seen their advantages. But every feature with pros has its cons, and you should know them:

  • Using multiple mixins can result in a mixins chain, which might make debugging difficult.
  • Increased dependencies.
  • High coupling. Every new feature added to the mixin class gets added to every child class.

Where to Go From Here?

You can download the complete project using the Download Materials button at the top or bottom of this tutorial.

In this article, you learned about:

  • Mixins
  • Hierarchy in Mixins
  • When and when not to use Mixins

I hope you enjoyed this article. If you want to learn more about Mixins and OOPs concepts in Dart, check out the following:

If you have any suggestions or questions or want to show off what you did to improve this project, join the discussion below.

[ad_2]

Source link