Flutter入门-数据传递

在android开发中,实现数据传递的方式有以下几种:1、intent携带参数;2、构造方法;3、Sharepreference本地保存;4、数据库保存;5、全局单例保存;6、EventBus;7、广播

在Flutter开发中,同样提供了相对应的方式:
1、Navigator页面切换的arguments属性
2、构造方法属性传值
3、Sharepreference本地保存
4、数据库保存
5、全局单例保存
6、EventBus
同时Flutter还提供了InheritedWidgetNotification

一、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('发送消息'),
      ),
    );
  }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值