如何每当页面出现在屏幕上时就重新加载页面 - 翩翩起舞 - Powered by Discuz!

问题描述 投票:0回答:1

有任何回调可用在flutter每次页面在屏幕上可见? 在ios有一些委托方法,如 viewWillAppear, viewDidAppear, viewDidload.

我想每当特定页面在屏幕上时,就调用一个API调用。

注意:我不要求应用程序的状态,如前景,背景,暂停,恢复。

谢谢

flutter dart flutter-layout
1个回答
1
投票

你不需要 StatefulWidget 用于每次显示屏幕时调用api。

在下面的示例代码中,按下浮动动作按钮导航到api调用界面,使用后退箭头返回,再次按下浮动动作按钮导航到api页面。

每当你访问这个页面时,api就会自动被调用。

import 'dart:async';

import 'package:flutter/material.dart';

main() => runApp(MaterialApp(home: HomePage()));

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => ApiCaller())),
      ),
    );
  }
}

class ApiCaller extends StatelessWidget {
  static int counter = 0;

  Future<String> apiCallLogic() async {
    print("Api Called ${++counter} time(s)");
    await Future.delayed(Duration(seconds: 2));
    return Future.value("Hello World");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Api Call Count: $counter'),
      ),
      body: FutureBuilder(
        future: apiCallLogic(),
        builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator();

          if (snapshot.hasData)
            return Text('${snapshot.data}');
          else
            return const Text('Some error happened');
        },
      ),
    );
  }
}

这就是简单的代码,零模板。


1
投票

具体到你的问题。

使用 initState 但请注意,您不能使用 async 召见 initState 因为它在初始化widget之前调用,顾名思义,就是在初始化widget之前调用。如果你想在UI创建之后做一些事情 didChangeDependencies 是伟大的。但千万不要用 build() 而不使用 FutureBuilderStreamBuilder

简单的例子来演示一下。

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(MaterialApp(home: ExampleScreen()));
}

class ExampleScreen extends StatefulWidget {
  ExampleScreen({Key key}) : super(key: key);

  @override
  _ExampleScreenState createState() => _ExampleScreenState();
}

class _ExampleScreenState extends State<ExampleScreen> {
  List data = [];
  bool isLoading = true;

  void fetchData() async {
    final res = await http.get("https://jsonplaceholder.typicode.com/users");
    data = json.decode(res.body);
    setState(() => isLoading = false);
  }

  // this method invokes only when new route push to navigator
  @override
  void initState() {
    super.initState();
    fetchData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: isLoading
            ? CircularProgressIndicator()
            : Text(data?.toString() ?? ""),
      ),
    );
  }
}

一些生命周期的方法 StatefulWidget's State 类。

initState():

描述该小组件所代表的用户界面部分。

框架在多种不同情况下调用此方法。

After calling initState.
After calling didUpdateWidget.
After receiving a call to setState.
After a dependency of this State object changes (e.g., an InheritedWidget referenced by the previous build changes).
After calling deactivate and then reinserting the State object into the tree at another location.

框架用本方法返回的widget替换该widget下面的子树,或者更新现有的子树,或者删除子树并填充一个新的子树,这取决于本方法返回的widget是否能更新现有子树的根,这由调用Widget.canUpdate决定。 阅读更多

didChangeDependencies():

当这个State对象的依赖关系发生变化时调用。

例如,如果前一次调用 build 引用的 InheritedWidget 后来发生了变化,框架会调用这个方法来通知这个对象的变化。

这个方法也会在 initState. 可以说 BuildContext.dependOnInheritedWidgetOfExactType 从这个方法。 阅读更多

build() (无状态小部件)

描述此小组件所代表的用户界面的一部分。

当此小组件被插入到给定 BuildContext 中的树中时,以及当此小组件的依赖关系发生变化时,框架会调用此方法(例如,一个 InheritedWidget 由这个小组件引用的变化)。) 阅读更多

didUpdateWidget(Widget oldWidget):

每当小组件配置改变时调用。

如果父小组件重建并要求树中的此位置更新以显示具有相同 runtimeType 和 "RuntimeType "的新小组件。 Widget.key框架会更新这个widget的属性。 State 对象来引用新的widget,然后使用之前的widget作为参数调用此方法。 阅读更多


1
投票

有些小组件是无状态的,有些是有状态的。如果是无状态的widget,那么只有值可以改变,但UI的改变不会呈现。

有状态的widget也是一样,它的值和UI都会改变。

现在,将研究方法。

  1. initState(): 这是在创建小组件时,但在构造函数调用后调用的第一个方法。

@override
void initState() {
   // TODO: implement initState
   super.initState();
}
  1. didChangeDependecies() - 当这个State对象的依赖关系发生变化时调用,在initState方法后立即调用。

@override
  void didChangeDependencies() {
    super.didChangeDependencies();
  }
  1. didUpdateWidget() - 每当widget配置被改变时,它就会被调用。框架总是在didUpdateWidget之后调用build。

@override
void didUpdateWidget (
   covariant Scaffold oldWidget
)
  1. setState() - 当State对象的内部状态要改变时,需要在setState方法中调用它。

 setState(() {});
  1. dispose() - 当这个对象从树中永久移除时被调用。

@override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }

0
投票

如果你想进行API调用,那么你必须(或者真的应该)使用一个StatefulWidget。

演练一下,比方说,你的有状态的widget收到一些id,它需要进行API调用。

每次你的widget接收到一个新的id(包括第一次),那么你就需要用这个id进行一个新的API调用。

所以使用 didUpdateWidget 以检查是否有 id 改变了,如果它改变了(就像当小组件出现时一样,因为旧的 id 将是 null)然后进行一个新的API调用(也设置适当的加载和错误状态!)

class MyWidget extends StatefulWidget {
  Suggestions({Key key, this.someId}) : super(key: key);

  String someId

  @override
  State<StatefulWidget> createState() => MyWidgetState();

}

class MyWidgetState extends State<MyWidget> {

  dynamic data;
  Error err;
  bool loading;

  @override
  Widget build(BuildContext context) {
     if(loading) return Loader();
     if(err) return SomeErrorMessage(err);
     return SomeOtherStateLessWidget(data);
  }


  @override
  void didUpdateWidget(covariant MyWidget oldWidget) { 
    super.didUpdateWidget(oldWidget);   

    // id changed in the widget, I need to make a new API call
    if(oldWidget.id != widget.id) update();
  }

  update() async {
    // set loading and reset error
    setState(() => {
      loading = true,
      err = null
    });

    try {
        // make the call
        someData = await apiCall(widget.id);
        // set the state
        setState(() => data = someData)
    } catch(e) {
        // oops an error happened
        setState(() => err = e)
    }

    // now we're not loading anymore
    setState(() => loading = false);
  }

}

我是Flutter的新手(真的,这个周末才开始玩),但它基本上重复了React范式,如果这对你有帮助的话。

个人喜好,我非常喜欢这种方法,而不是使用这种方法。FutureBuilder 现在,就像我说的,我是全新的)。逻辑只是更容易推理(对我来说)。

© www.soinside.com 2019 - 2024. All rights reserved.