在android开发中,实现数据传递的方式有以下几种:1、intent携带参数;2、构造方法;3、Sharepreference本地保存;4、数据库保存;5、全局单例保存;6、EventBus;7、广播
在Flutter开发中,同样提供了相对应的方式:
1、Navigator页面切换的arguments属性
2、构造方法属性传值
3、Sharepreference本地保存
4、数据库保存
5、全局单例保存
6、EventBus
同时Flutter还提供了InheritedWidget和Notification
一、Navigator的arguments属性
1、动态路由传参
push<T extends Object?>(BuildContext context, Route<T> route)
对于android设备,通常使用MaterialPageRoute
MaterialPageRoute({
required this.builder,
super.settings,
this.maintainState = true,
super.fullscreenDialog,
})
参数builder
typedef WidgetBuilder = Widget Function(BuildContext context);
builder是一个参数为BuildContext类型,返回值为widget的匿名函数。
参数settings
class RouteSettings {
/// Creates data used to construct routes.
const RouteSettings({
this.name,
this.arguments,
});
/// Creates a copy of this route settings object with the given fields
/// replaced with the new values.
RouteSettings copyWith({
String? name,
Object? arguments,
}) {
return RouteSettings(
name: name ?? this.name,
arguments: arguments ?? this.arguments,
);
}
/// The name of the route (e.g., "/settings").
///
/// If null, the route is anonymous.
final String? name;
/// The arguments passed to this route.
///
/// May be used when building the route, e.g. in [Navigator.onGenerateRoute].
final Object? arguments;
String toString() => '${objectRuntimeType(this, 'RouteSettings')}("$name", $arguments)';
}
参数settings是RouteSettings类,该类包含两个属性,name属性,为该路由的名字;属性arguments的类型是object,说明可以是任意类型的数据。
自定义的参数类
class Arguments {
String _name = "";
int _age = 0;
String get name => _name;
set name(String value) {
_name = value;
}
int get age => _age;
set age(int value) {
_age = value;
}
String toString() {
return 'Arguments{_name: $_name, _age: $_age}';
}
}
Arguments arguments = Arguments();
arguments.name = "我是从上个页面传的";
arguments.age = 18;
Navigator.push(context,MaterialPageRoute(
builder: (context) => SecondPage(),
settings: RouteSettings(name: 'second', arguments: arguments)))
命名路由传参
函数原型
pushNamed<T extends Object?>(
BuildContext context,
String routeName, {
Object? arguments,
})
context:上下文环境
routeName:路由名称
arguments:参数(可选)
Arguments arguments = Arguments();
arguments.name = "我是从上个页面传的";
arguments.age = 18;
Navigator.pushNamed(context, "second", arguments: arguments);
二、构造方法传参
import 'package:flutter/material.dart';
import 'package:flutter_hello/arguments.dart';
class ConstructHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
child: Text('跳转下一页'),
onTap: () {
Arguments arguments = Arguments();
arguments.name = "我是来源于首页";
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
ConstructSecondPage(arguments)));
},
),
),
);
}
}
class ConstructSecondPage extends StatelessWidget {
Arguments arguments;
ConstructSecondPage(this.arguments);
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Text('${arguments.name}'),
),
),
);
}
}
Navigator使用抛出的异常:
Navigator operation requested with a context that does not include a Navigator.
解决方案:
如上面demo,MaterialApp的home指向的widget使用StatelessWidget或者StatefulWidget包一层即可
三、SharedPreferences
添加相关依赖
dependencies:
shared_preferences: ^2.0.15
使用
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class MySharedPreference extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: SharedPreferenceHome(),
);
}
}
class SharedPreferenceHome extends StatelessWidget {
void setString(String key, String value) async {
var sp = await SharedPreferences.getInstance();
sp.setString(key, value);
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
child: Text('下一个页面'),
onTap: () {
setString('arguments', '我是SharedPreferences传值');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SharedPreferenceSecond()));
},
),
),
);
}
}
class SharedPreferenceSecond extends StatefulWidget {
State<SharedPreferenceSecond> createState() => _SharedPreferenceSecondState();
}
class _SharedPreferenceSecondState extends State<SharedPreferenceSecond> {
String arguments = "";
void getString(String key, [String defaultValue = '']) async {
SharedPreferences sp = await SharedPreferences.getInstance();
arguments=sp.getString(key) ?? defaultValue;
setState(() {
});
}
void initState() {
super.initState();
getString('arguments');
}
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Text('${arguments}'),
),
),
);
}
}
SharedPreferences的所有操作都是异步的,所以需要进一步包装。
四、数据库(sqflite)
1、添加依赖
dependencies:
sqflite: ^2.2.0+3
2、自定义DataBase帮助类
class SQLHelper {
static Future<Database> getDb() async {
// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'hello.db');
// open the database
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
// When creating the db, create the table
await db.execute(
'CREATE TABLE IF NOT EXISTS People (id INTEGER PRIMARY KEY, name TEXT, age INTEGER, num INTEGER)');
});
return database;
}
}
3、自定义类
///自定义people类
class People {
String _name="";
int _age=0;
int _num=0;
People();
String get name => _name;
set name(String value) {
_name = value;
}
int get age => _age;
set age(int value) {
_age = value;
}
int get num => _num;
set num(int value) {
_num = value;
}
People.fromJson(Map<String, dynamic> peopleJson) {
_name = peopleJson['name'];
_age = peopleJson['age'];
_num = peopleJson['num'];
}
Map<String, dynamic> toJson() {
return {"name": _name, "age": _age, "num": _num};
}
}
4、实现插入类到数据库
void insertPeople(People people) async {
final Database db = await SQLHelper.getDb();
db.insert('People', people.toJson());
}
5、实现查询数据库
Future<People?> getPeople() async {
final Database db = await SQLHelper.getDb();
List<Map<String, dynamic>> list =
await db.query('People', columns: ['name', 'age', 'num']);
if (list != null && list.length > 0) {
return People.fromJson(list.first);
}
return null;
}
完整的dart文件
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class SQLHelper {
static Future<Database> getDb() async {
// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'hello.db');
// open the database
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
// When creating the db, create the table
await db.execute(
'CREATE TABLE IF NOT EXISTS People (id INTEGER PRIMARY KEY, name TEXT, age INTEGER, num INTEGER)');
});
return database;
}
}
///自定义people类
class People {
String _name="";
int _age=0;
int _num=0;
People();
String get name => _name;
set name(String value) {
_name = value;
}
int get age => _age;
set age(int value) {
_age = value;
}
int get num => _num;
set num(int value) {
_num = value;
}
People.fromJson(Map<String, dynamic> peopleJson) {
_name = peopleJson['name'];
_age = peopleJson['age'];
_num = peopleJson['num'];
}
Map<String, dynamic> toJson() {
return {"name": _name, "age": _age, "num": _num};
}
}
///首页
class MySqfliteHome extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: MySqfliteHomePage(),
);
}
}
class MySqfliteHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
child: Text('下一页'),
onTap: () {
People people = new People();
people.name = 'Hello';
people.age = 18;
people.num = 2022;
insertPeople(people);
Navigator.push(context,
MaterialPageRoute(builder: (context) => MySqfliteSecondPage()));
},
),
),
);
}
void insertPeople(People people) async {
final Database db = await SQLHelper.getDb();
db.insert('People', people.toJson());
}
}
///第二页页面
class MySqfliteSecondPage extends StatefulWidget {
State<MySqfliteSecondPage> createState() => _MySqfliteSecondPageState();
}
class _MySqfliteSecondPageState extends State<MySqfliteSecondPage> {
People people = People();
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
Text('姓名:${people.name}'),
Text('年龄:${people.age}'),
Text('编号:${people.num}')
],
),
),
),
);
}
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// getPeople().then((value) {
// people = value!;
// setState(() {});
// });
initData();
});
}
void initData() async {
people = (await getPeople())!;
setState(() {});
}
Future<People?> getPeople() async {
final Database db = await SQLHelper.getDb();
List<Map<String, dynamic>> list =
await db.query('People', columns: ['name', 'age', 'num']);
if (list != null && list.length > 0) {
return People.fromJson(list.first);
}
return null;
}
}
五、全局单例实现(多用于不需要保存到本地的全局属性)
1、单例的定义
class GlobalSingleInstance {
///单例写法1
// GlobalSingleInstance._internal();
//
// factory GlobalSingleInstance() => _instance;
//
// static late final GlobalSingleInstance _instance = GlobalSingleInstance._internal();
///单例写法2
factory GlobalSingleInstance() => _getShared();
static GlobalSingleInstance get _instance => _getShared();
static GlobalSingleInstance? instance;
GlobalSingleInstance._internal() {
// 初始化
}
static GlobalSingleInstance _getShared() {
instance ??= GlobalSingleInstance._internal();
return instance!;
}
int _gloableNum = 0;
int get gloableNum => _gloableNum;
set gloableNum(int value) {
_gloableNum = value;
}
}
2、单例多页面调用
import 'package:flutter/material.dart';
class GlobalSingleInstance {
///单例写法1
// GlobalSingleInstance._internal();
//
// factory GlobalSingleInstance() => _instance;
//
// static late final GlobalSingleInstance _instance = GlobalSingleInstance._internal();
///单例写法2
factory GlobalSingleInstance() => _getShared();
static GlobalSingleInstance get _instance => _getShared();
static GlobalSingleInstance? instance;
GlobalSingleInstance._internal() {
// 初始化
}
static GlobalSingleInstance _getShared() {
instance ??= GlobalSingleInstance._internal();
return instance!;
}
int _gloableNum = 0;
int get gloableNum => _gloableNum;
set gloableNum(int value) {
_gloableNum = value;
}
}
class GloableSingleInstance extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: GloableSingleInstanceHome(),
);
}
}
class GloableSingleInstanceHome extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
child: Text('下一页'),
onTap: () {
GlobalSingleInstance._instance.gloableNum = 20;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GloableSingleInstanceSecond()));
},
),
),
);
}
}
class GloableSingleInstanceSecond extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Text('当前数据:${GlobalSingleInstance._instance.gloableNum}'),
),
);
}
}
六、EventBus实现
EventBus是基于事件总线,采用订阅-观察者模式,可以订阅指定的‘事件’,也可以订阅所有‘事件’
1、添加依赖
dependencies:
event_bus: ^2.0.0
2、定义监听的对象
class CustomEvent {
String msg;
CustomEvent(this.msg);
}
3、订阅监听
void initState() {
super.initState();
subscription = eventBus.on<CustomEvent>().listen((event) {
setState(() {
_msg = event.msg;
});
});
}
4、取消订阅监听
void dispose() {
subscription.cancel();
super.dispose();
}
5、发布消息
eventBus.fire(CustomEvent('总线发射${Random().nextInt(100)}'));
完整代码
import 'dart:async';
import 'dart:math';
import 'package:event_bus/event_bus.dart';
import 'package:flutter/material.dart';
EventBus eventBus = EventBus();
class ShareDataWithEventBus extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: MyFirstPage(),
);
}
}
class CustomEvent {
String msg;
CustomEvent(this.msg);
}
class MyFirstPage extends StatefulWidget {
State<MyFirstPage> createState() => _MyFirstPageState();
}
class _MyFirstPageState extends State<MyFirstPage> {
late StreamSubscription<CustomEvent> subscription;
String _msg="";
void initState() {
super.initState();
subscription = eventBus.on<CustomEvent>().listen((event) {
setState(() {
_msg = event.msg;
});
});
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(
'$_msg',
style: TextStyle(color: Colors.blue, fontSize: 20),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => MySecondPage()));
},
),
);
}
void dispose() {
subscription.cancel();
super.dispose();
}
}
class MySecondPage extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('使用Event bus'),
centerTitle: true,
leading: BackButton(
onPressed: () {
Navigator.pop(context);
eventBus.fire(CustomEvent('总线发射${Random().nextInt(100)}'));
},
),
),
body: Text('我是第二个页面'),
),
);
}
}
七、基于InheritedWidget
InheritedWidget可以实现数据从父控件传递到子控件。
1、继承InheritedWidget
class CountContainer extends InheritedWidget {
final int count;
CountContainer({
required this.count,
required Widget child}): super(child: child);
bool updateShouldNotify(CountContainer oldWidget) => count != oldWidget.count;
static CountContainer? of(BuildContext context) =>context.dependOnInheritedWidgetOfExactType();
}
2、应用
class WidgetParentToChild extends StatefulWidget {
State<WidgetParentToChild> createState() => _WidgetParentToChildState();
}
class _WidgetParentToChildState extends State<WidgetParentToChild> {
int _count=0;
void _incrementCounter(){
_count=Random().nextInt(100);
setState(() {});
}
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: (){
_incrementCounter();
},
),
body: Center(
child: CountContainer(
count: _count,
child: CountContainerChild(),
),
),
),
);
}
}
完整代码
import 'dart:math';
import 'package:flutter/material.dart';
class WidgetParentToChild extends StatefulWidget {
State<WidgetParentToChild> createState() => _WidgetParentToChildState();
}
class _WidgetParentToChildState extends State<WidgetParentToChild> {
int _count=0;
void _incrementCounter(){
_count=Random().nextInt(100);
setState(() {});
}
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: (){
_incrementCounter();
},
),
body: Center(
child: CountContainer(
count: _count,
child: CountContainerChild(),
),
),
),
);
}
}
class CountContainer extends InheritedWidget {
final int count;
CountContainer({
required this.count,
required Widget child}): super(child: child);
bool updateShouldNotify(CountContainer oldWidget) => count != oldWidget.count;
static CountContainer? of(BuildContext context) =>context.dependOnInheritedWidgetOfExactType();
}
class CountContainerChild extends StatelessWidget{
Widget build(BuildContext context) {
final int number=CountContainer.of(context)!.count;
return Text("$number", style: TextStyle(color: Colors.amber, fontSize: 40));
}
}
八、基于Notification
Notification可以实现数据由子控件传递到父控件
1、继承Notification
class CustomNotification extends Notification {
final String msg;
CustomNotification(this.msg);
}
2、NotificationListener监听
class ShareDataFromChildToParent extends StatefulWidget {
State<ShareDataFromChildToParent> createState() =>
_ShareDataFromChildToParentState();
}
class _ShareDataFromChildToParentState extends State<ShareDataFromChildToParent> {
String _msg = "";
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: NotificationListener<CustomNotification>(
child: Center(
child: Column(
children: [
ShareDataChild(),
Text(
'$_msg',
style: TextStyle(color: Colors.black, fontSize: 20),
),
],
),
),
onNotification: (notification) {
setState(() {
_msg = notification.msg;
print(_msg);
});
return false;
},
),
),
);
}
}
3、使用dispatch发送数据
onPressed: () => CustomNotification('Hi,I`am from child')
.dispatch(context)
4、完整代码
import 'package:flutter/material.dart';
/**
* 使用Notification
*/
class ShareDataFromChildToParent extends StatefulWidget {
State<ShareDataFromChildToParent> createState() =>
_ShareDataFromChildToParentState();
}
class _ShareDataFromChildToParentState extends State<ShareDataFromChildToParent> {
String _msg = "";
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: NotificationListener<CustomNotification>(
child: Center(
child: Column(
children: [
ShareDataChild(),
Text(
'$_msg',
style: TextStyle(color: Colors.black, fontSize: 20),
),
],
),
),
onNotification: (notification) {
setState(() {
_msg = notification.msg;
print(_msg);
});
return false;
},
),
),
);
}
}
class CustomNotification extends Notification {
final String msg;
CustomNotification(this.msg);
}
class ShareDataChild extends StatelessWidget{
Widget build(BuildContext context) {
return Center(
child: MaterialButton(
onPressed: () => CustomNotification('Hi,I`am from child')
.dispatch(context),
child: Text('发送消息'),
),
);
}
}