SoFunction
Updated on 2025-04-11

Detailed explanation of the use of mixin in Flutter

What is mixin

How should mixin be understood? For me who came from the Java department, this is a new concept, and there is no clear definition of the introduction of various materials. From a personal understanding, you can imagine it as an interface in Kotlin (the difference between it and Java is that it can have non-abstract properties and methods), while multiple mixins can be overlaid with each other to achieve combination, providing very great flexibility and can also achieve effects similar to multiple inheritance.

Page table page

This is a normal display data, pulling up a list of more data to load.

One of the types isList<T>listData, page data is used for paging, isLoading is used to determine whether data is loading, scrollController is used for list controller

If there are a large number of such pages, you can use mixin to process them, which inevitably leads to a lot of duplicate code.

import 'package:flutter/';
import 'package:flutter_app/app/model/';
import 'package:flutter_app/app/shared/api/';
import 'package:dio/';
import 'dart:convert';

import 'package:flutter_app/app/shared/mixins/list_more_data_mixin.dart';

/// List pageclass RecommendView extends StatefulWidget {
 @override
 _RecommendViewState createState() =&gt; _RecommendViewState();
}

class _RecommendViewState
 extends ListMoreDataBase&lt;ListViewJsonData, RecommendView&gt;
 with ListMoreDataMixin&lt;ListViewJsonData, RecommendView&gt; {
 @override
 Future&lt;List&lt;ListViewJsonData&gt;&gt; getData() async {
 String data = await (
 "api/getOneLevel",
 parameters: ({
 'page': page,
 'limit': '10',
 }),
 );
 ListViewJson _json = ((data));
 return _json.data;
 }

 @override
 void initState() {
 print('init widget');
 ();
 }

 @override
 void dispose() {
 print('dispose widget');
 ();
 }

 @override
 Widget build(BuildContext context) {
 return Scaffold(
 backgroundColor: ,
 appBar: AppBar(title: Text('return')),
 body: Stack(
 children: &lt;Widget&gt;[
  NotificationListener&lt;ScrollNotification&gt;(
  onNotification: onNotification,
  child: (
  controller: scrollController,
  itemCount: ,
  itemBuilder: (BuildContext context, int index) =&gt;
   TeamListItem(listData[index]),
  ),
  ),
  isLoading ? Center(child: CircularProgressIndicator()) : Container()
 ],
 ),
 );
 }
}

mixin

import 'package:flutter/';

abstract class ListMoreDataBase&lt;T, K extends StatefulWidget&gt; extends State&lt;K&gt; {
 /// Get asynchronous data Future&lt;List&lt;T&gt;&gt; getData();
}

/// existmixin ListMoreDataMixin&lt;T, K extends StatefulWidget&gt; on ListMoreDataBase&lt;T, K&gt; {
 @override
 void initState() {
 print('init');
 ();
 initData();
 }

 @override
 void dispose() {
 print('dispose');
 ();
 scrollController?.dispose();
 }

 /// Data list List&lt;T&gt; listData = [];

 /// Pagination int page = 1;

 /// Is the data loading bool isLoading = false;

 /// Scrollbar controller ScrollController scrollController = ScrollController();

 /// Initialize data Future&lt;void&gt; initData() async {
 setState(() {
 isLoading = true;
 });

 List&lt;T&gt; data = await getData();
 if (!mounted) return;
 setState(() {
 listData = data;
 isLoading = false;
 });
 }

 /// Pull-up load more Future&lt;void&gt; loadMore() async {
 setState(() {
 isLoading = true;
 page += 1;
 });

 List&lt;T&gt; data = await getData();

 if () {
 page--;
 }

 setState(() {
 (data);
 isLoading = false;
 });
 }

 bool canLoadMore(ScrollNotification scroll) {
 return !isLoading &amp;&amp;
  &lt;= ;
 }

 bool onNotification(ScrollNotification scroll) {
 if (canLoadMore(scroll)) {
 loadMore();
 }
 return true;
 }
}

Note:

  • dart is single inheritance
  • In the class, the properties and methods of mixin can be overridden, and the properties and methods of mixin can also be called with super can be used to call the properties and methods of mixin in the class.
  • The life cycle above prints init widget -> init -> dispose widget -> dispose

ps: The following shows how mixin is used in Dart from simple to complex

The easiest mixin

mixin TestMixin {
 void test() {
 print('test');
 }
 int testInt = 1;
 void test2();
}
 
class Test with TestMixin {
 @override
 test2() {
 print('test2');
 }
}

void main() {
 Test().test();  // test
 print(Test().testInt); // 1
 Test().test2();  // test2
}

The mixin itself can be abstract, can define various method attributes, or it can be abstract, and can be implemented by subsequent classes.

Based on a certain type of mixin

class BaseObject {
 void method() {
 print('call method');
 }
}
mixin TestMixin on BaseObject{
 void test() {
 print('test');
 }
 int testInt = 1;
 void test2() {
 method();
 }
}
 
class Test extends BaseObject with TestMixin {
}
 
void main() {
 Test().test();  // test
 print(Test().testInt); // 1
 Test().test2();  // call method
}

When using the on keyword, it means that the mixin can only be used in the subclass of that class. Then obviously, the methods and properties defined by that class can be called in the mixin

Multiple mixins

mixin TestMixin {
 void test() {
 print('test');
 }
 
 int testInt = 1;
 
 void test2();
}
 
mixin TestMixin2 {
 int testInt = 2;
 
 void test3() {
 print('test3');
 }
}
 
class Test with TestMixin, TestMixin2 {
 @override
 test2() {
 print('test2');
 }
}
 
void main() {
 Test().test();  // test
 print(Test().testInt); // 2
 Test().test2();  // test2
 Test().test3();  // test3
}

If you change the order of TestMixin and TestMixin2:

mixin TestMixin {
 void test() {
 print('test');
 }
 
 int testInt = 1;
 
 void test2();
}
 
mixin TestMixin2 {
 int testInt = 2;
 
 void test3() {
 print('test3');
 }
}
 
class Test with TestMixin2, TestMixin {
 @override
 test2() {
 print('test2');
 }
}
 
void main() {
 Test().test();  // test
 print(Test().testInt); // 1
 Test().test2();  // test2
 Test().test3();  // test3
}

If there is a conflicting part of the mixin, the previous one will be overwritten, and if there is no conflict, it will be retained. Therefore, there can be a situation where the subsequent mixin modify part of the logic of the previous mixin. It does not require direct inheritance to achieve overwritten, avoiding more complex inheritance relationships

"Multiple Inheritance"
mixin TestMixin on BaseClass {
 void init() {
 print('TestMixin init start');
 ();
 print('TestMixin init end');
 }
}
 
mixin TestMixin2 on BaseClass {
 void init() {
 print('TestMixin2 init start');
 ();
 print('TestMixin2 init end');
 }
}
 
class BaseClass {
 void init() {
 print('Base init');
 }
 BaseClass() {
 init();
 }
}
 
class TestClass extends BaseClass with TestMixin, TestMixin2 {
 
 @override
 void init() {
 print('TestClass init start');
 ();
 print('TestClass init end');
 
 }
}
 
void main() {
 TestClass();
 /// TestClass init start
 /// TestMixin2 init start
 /// TestMixin init start
 /// Base init
 /// TestMixin init end
 /// TestMixin2 init end
 /// TestClass init end
}

If you are a little confused, you can see that this has actually achieved the effect of multiple inheritance. It is more troublesome to write and to some extent it is less prone to errors (relative to C++). . . There are the best and most complex examples in the source code - WidgetsFlutterBinding, which is defined as follows:

class WidgetsFlutterBinding 
extends BindingBase with GestureBinding, 
ServicesBinding, 
SchedulerBinding, 
PaintingBinding, 
SemanticsBinding,
 RendererBinding,
 WidgetsBinding 
{
}

The specific analysis of WidgetsFlutterBinding is gone, please read the source code yourself~~

Summarize

This is the end of this article about the use of mixin in Flutter. For more related content on flutter mixin, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!