👀

コールバック関数とは何ぞや?

2023/06/06に公開

登録画面でtodoを登録して、home画面に画面遷移をしても登録したリストが表示されない!

どうもこんにちはflutter初心者のつきゆびです🔰

driftを使って簡単なtodoリストを作った時にhome画面と登録画面を作りました。

登録画面でtodoを登録して、home画面に戻っても登録したリスト表示されない!
なぜか更新されてない!

それを解決してくれたのがコールバック関数でした

それを紹介したいと思います

まず用語の説明です
  • 関数の特徴:

関数は、一連の処理をまとめたものです。特定のタスクや計算を実行するための手続きが含まれています。
関数は、呼び出されることでその中の処理が実行されます。

  • コールバック関数の概要:

コールバック関数は、他の関数に引数として渡される関数です。
コールバック関数は、ある条件やイベントが発生した時に呼び出されることがあります。

  • コールバック関数の利点:

コールバック関数を使用すると、処理の流れを柔軟に制御することができます。
関数を引数として渡すことで、処理の一部を他の関数に委ねることができます。

  • コールバック関数の例:

コールバック関数の一つの例は、イベントハンドリングです。たとえば、ボタンがクリックされたときに呼び出される関数を指定することができます。
また、非同期処理でもコールバック関数が使用されます。非同期処理では、処理が完了した後にコールバック関数が呼び出されることがあります。

コールバック関数の例え話

お母さんが子供に「お風呂が終わったら教えてね」と言ってお風呂に入れる場合を考えてみましょう。

お風呂が終わったとき、子供はお母さんに教える(コールバックする)ことで、お風呂から出るタイミングを制御します。
お母さんは子供のコールバックを受け取り、それに応じて次の処理(例えば、おやつを用意する)を行います。
このように、コールバック関数は特定のイベントや条件に応じて呼び出される関数であり、処理の流れを柔軟に制御するための重要な概念です。

以下がコードです

タスクを追加する画面(TodoInputScreen)で登録が行われた後にコールバック関数を呼び出し、ホーム画面(MyHomePage)でタスクリストを更新するという仕組みを実装しました。

home_page
import 'package:flutter/material.dart';
import 'package:todo/db/database.dart';
import 'package:todo/screen/todo_input_screen.dart';

import '../widget/custom_listtile.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<Task> _tasksList = [];
  bool isOpened = false;

  
  void initState() {
    super.initState();
    _getAllTask();
  }
/*
_getAllTaskメソッドは、データベースから全てのタスクを取得してリストに格納する処理です。

onTaskAddedコールバック関数の中で_getAllTaskを呼び出すことで、
新しいタスクが追加された後にタスクリストを更新して表示することができるようになります。
*/
  void _getAllTask() async {
    _tasksList = await MyDatabase().allTasks;
    setState(() {});
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("リスト"),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => TodoInputScreen(
                onTaskAdded: (taskName) {
                  _getAllTask(); // 新しいタスクが追加されたのでタスクリストを更新
                },
              ),
            ),
          );
        },
        label: Text("追加する"),
        icon: Icon(Icons.add),
      ),
      body: Padding(
        padding: const EdgeInsets.all(10.0),
        child: ListView.builder(
            itemCount: _tasksList.length,
            itemBuilder: (context, index) {
              return CustomListTile(
                title: _tasksList[index].name,
                isChecked: false,
                onTap: () {
                  // タップされたときの処理
                },
                onDelete: () {
                  // 削除されたときの処理
                },
              );
            }),
      ),
    );
  }
}

タスクを追加する画面

TodoInputScreen
import 'package:drift/native.dart';
import 'package:flutter/material.dart';
import 'package:todo/db/database.dart';

class TodoInputScreen extends StatefulWidget {
  final Function(String) onTaskAdded; // コールバック関数

  const TodoInputScreen({Key? key, required this.onTaskAdded})
      : super(key: key);

  
  State<TodoInputScreen> createState() => _TodoInputScreenState();
}

class _TodoInputScreenState extends State<TodoInputScreen> {
  final TextEditingController _textEditingController = TextEditingController();
  final int maxCharacterCount = 10;
  final formKey = GlobalKey<FormState>();

  
  void dispose() {
    _textEditingController.dispose();
    super.dispose();
  }

  _submitTask() async {
    if (_textEditingController.text == "") {
      return;
    }
    try {
      var task = Task(name: _textEditingController.text, isMemorized: false);
      await MyDatabase().insertTask(task);
      /*
      TodoInputScreenのコンストラクタにonTaskAddedというコールバック関数を追加しました。
      そして、新しいタスクが追加された後にこのコールバック関数が呼び出されます。
      */
      widget.onTaskAdded(task.name); // コールバック関数を呼び出してタスクを追加したことを通知
      _textEditingController.clear();
      Navigator.pop(context);
    } on SqliteException catch (e) {
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('New Task'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Form(
              key: formKey,
              child: TextFormField(
                  autofocus: true,
                  controller: _textEditingController,
                  maxLength: maxCharacterCount,
                  decoration: InputDecoration(
                    labelText: 'Task Name',
                  )),
            ),
            SizedBox(height: 26.0),
            ElevatedButton(
              onPressed: _submitTask,
              child: Text('Add Task'),
            ),
          ],
        ),
      ),
    );
  }
}

まとめ

この投稿では、FlutterのToDoリストアプリの実装例を通じて、コールバック関数の利用方法を紹介しました。具体的には、
タスクを追加する画面で登録 → コールバック関数を呼び出し → ホーム画面でタスクリストを更新するという仕組みを実装しました。

コードとともに、コールバック関数の概要や利点、具体的な例についても説明しました。これにより、コールバック関数がどのように役立つのか、どのように実装するのかがより明確に理解できるでしょう。

この投稿を通じて、私と同じくFlutter初心者の方にコールバック関数の理解と実装の手助けができれば幸いです。もし他に質問や補足があればお知らせください。

最後まで読んでいただきありがとうございました。

Discussion