最近在捣鼓Flutter的时候, 一直在解决有关fileProvider的问题. 当需要打开安卓设备自带的文件管理器时, 一直报错
exposed beyond app through Intent.getData() 在配置 FileProvider相关权限后, 依旧不行, 貌似需要原生调用.这估计就需要flutter与原生相互调用了, 奈何我暂时没有了解过有关原生开发的信息. 就只能先去解决一些页面交互的问题.

event_bus

Flutter 的event_bus扩展, 可以简单的实现一个 发布<->订阅 模型. 如果需要其他的跨组建数据共享, 则可以选择 Provider 扩展.

举个例子, 当我们在 login.dart 中登录后, 需要在 user.dart 中更新信息时. 我们可以直接在 user.dart 中订阅一个事件, 当用户在 login.dart 中登录后发布一个信息, user.dart中监听到事件则重新获取用户信息, 重新渲染页面.

实现

目前 我需要的场景是, 当用户登录后, 直接返回首页, 刷新信息.

大致的文件结构为:

1
2
3
4
5
6
7
8
9
|_ main.dart
|_ account |_ login.dart
|
|_ home |_ index.dart
| |_ home.dart
| |_ user.dart
|
|_ event |_ bus.dart
|_ account_event.dart

其中 main.dart 是我们的启动文件, account/login 为登录页面, home/index 为首页的 入口文件, 有 user 和 home 两个tab.

首先 我们可以新建一个 ~/event/bus.dart 文件, 来全局共享 EventBus 类

1
2
3
4
5
6
7
8
9
10
import 'package:event_bus/event_bus.dart';

// event/bus.dart
class Bus {
static late EventBus eventBus;

static init() {
Bus.eventBus = EventBus();
}
}

接着在 main.dart 中初始化 event_bus

1
2
3
4
5
6
7
/* code */
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Bus.init();

runApp(const App());
}

在发布/订阅消息时, 我们需要一个模型来指定参数, 比如这里 我们只需要一个简单的登录通知 >

1
2
3
4
5
class AccountEvent {
final String type;

const AccountEvent(this.type);
}

接着 我们可以在需要的页面(user.dart)订阅通知 >

1
2
3
4
5
6
7
8
9
10
11
import 'package:example/event/account_event.dart';
import 'package:example/event/bus.dart';

/* code */

Future<void> _listen() async {
Bus.eventBus.on<AccountEvent>().listen((event) {
LogUtil.v(event.type)
/* code */
});
}

此时 当用户登录后, 我们可以直接 通过 EventBus.fire 发布信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import 'package:example/event/account_event.dart';
import 'package:example/event/bus.dart';

Future<void> _login() async {
httpR.post('/login',{
'user': xx,
'pass': xx,
}).then((res) async {
if (res['code'] == 0){
prefs.setString('token', res['token']); // 存储凭证
Bus.eventBus.fire(const AccountEvent('login'));
Navigator.of(context).pop();
}
})
}

此时, 当用户登录后, 在user.dart中 我们期待会返回一个 内容为 ‘login’ 字符串