コールバック関数とは何ですか?


684

コールバック関数とは何ですか?


8
ここで見つけることができます:stackoverflow.com/a/9652434/3343174コールバックに関する最良の説明
Fakher


詳細な説明については2番目の回答を参照してください
Donato

youtube.com/watch?v=xHneyv38Jro
Sameer Sinha

回答:


680

のろわれたものの名前が原因で、開発者はコールバックが何であるか混乱することがよくあります。

コールバック関数は、次のような関数です。

  • 別の機能からアクセスできる
  • 最初の関数が完了した場合、最初の関数の後に呼び出されます

コールバック関数がどのように機能するかを想像する良い方法は、それが渡される関数の「バックで呼び出される」関数であるということです。

たぶん、より良い名前は「後の呼び出し」関数でしょう。

この構成は、前のイベントが完了するたびにアクティビティが発生する非同期動作に非常に役立ちます。

疑似コード:

// A function which accepts another function as an argument
// (and will automatically invoke that function when it completes - note that there is no explicit call to callbackFunction)
funct printANumber(int number, funct callbackFunction) {
    printout("The number you provided is: " + number);
}

// a function which we will use in a driver function as a callback function
funct printFinishMessage() {
    printout("I have finished printing numbers.");
}

// Driver method
funct event() {
   printANumber(6, printFinishMessage);
}

event()を呼び出した場合の結果:

The number you provided is: 6
I have finished printing numbers.

ここでの出力の順序は重要です。後でコールバック関数が呼び出されるため、「数字の出力が完了しました」が最初ではなく最後に出力されます。

コールバックは、ポインター言語での使用により、いわゆるコールバックです。これらのいずれかを使用しない場合は、「コールバック」という名前に労力を費やさないでください。親メソッドが呼び出されたとき(ボタンクリック、タイマーティックなどの条件)、そのメソッド本体が完了したときなど、別のメソッドへの引数として提供されるメソッドを説明するための単なる名前であることを理解してください。次に、コールバック関数が呼び出されます。

一部の言語は、複数のコールバック関数引数がサポートされている構造をサポートし、親関数の完了方法に基づいて呼び出されます(つまり、1つのコールバックは、親関数が正常に完了した場合に呼び出され、別のコールバックは、親関数がスローした場合に呼び出されます。特定のエラーなど)。


31
あなたの例は素晴らしいですが、用語が「コールバック」である理由はわかりません。どのような意味の「ライフ」が「コールバック」されますか?
CodyBugstein 2013

4
こんにちは、についてonce its parent method completes, the function which this argument represents is then called。関数が引数として別の関数に渡されたが、親関数のランタイムの途中から呼び出されたparent(cb) {dostuff1(); cb(); dostuff2()}場合、callback関数とは見なされませんか?
Max Yari 2015

2
@MaxYari:私見、それはまだコールバックと見なされます。ここで重要なことは、親関数が何らかの方法で入力関数(別名コールバック)を使用することです。途中または最後に、または条件が満たされた場合に呼び出すことができます。
Kamran Bigdely 2016

12
@ 8bitjunkieありがとうございました-しかし、printANumber関数内でどういう意味のLifeOfメソッドが呼び出されますか?
BKSpurgeon 2016年

2
これはまったく当てはまりません。「最初の関数が完了すると自動的に呼び出されます」。コールバックを実行する必要はなく、自動的に実行する必要もありません。実際、親関数が完了する前にコールバックが完了することも珍しくありません。私は、人々がコールバックを「後で」実行される関数であると説明する方法を非常に嫌っています。それらについて学んでいる人々にとって、それは非常に混乱しています。簡単に言えば、コールバックは、他の関数の引数として渡される関数です。限目。より適切な説明には、関数参照に対するWHYコールバックの説明が含まれます。
ヨルダン

224

不透明な定義

コールバック関数は、別のコードに提供する関数で、そのコードから呼び出すことができます。

考案された例

なぜこれをしたいのですか?呼び出す必要のあるサービスがあるとしましょう。サービスがすぐに戻る場合は、次のようにします。

  1. あれを呼べ
  2. 結果を待つ
  3. 結果が出たら続行する

たとえば、サービスがfactorial関数だったとします。の値が必要な場合は5!、を呼び出してfactorial(5)、次の手順を実行します。

  1. 現在の実行場所が保存されます(スタックに保存されますが、それは重要ではありません)

  2. 実行はに渡されます factorial

  3. ときにfactorial完了するが、それは結果を置くどこかで、あなたはそれを得ることができます

  4. 実行は[1]にあった場所に戻ります

ここでfactorial、非常に長い時間がかかったとしましょう。膨大な数を与えているため、スーパーコンピューティングクラスタで実行する必要があるためです。結果が返されるまでに5分かかると想定しているとします。あなたは出来る:

  1. デザインを維持し、眠っている夜にプログラムを実行して、半分の時間だけ画面を見つめないようにします。

  2. 一方、他のことを行うには、あなたのプログラムを設計しfactorial、そのことをやっています

2番目のオプションを選択すると、コールバックが機能する場合があります。

エンドツーエンドの設計

コールバックパターンを利用するにfactorialは、次の方法で呼び出すことができる必要があります。

factorial(really_big_number, what_to_do_with_the_result)

2番目のパラメーターはwhat_to_do_with_the_result、戻り値の前にその結果を呼び出すことをfactorial期待して、に送信する関数ですfactorial

はい、これは、factorialコールバックをサポートするように記述されている必要があることを意味します。

次に、コールバックにパラメーターを渡せるようにしたいとします。あなたはそれを呼ぶつもりはないので、今はできませんfactorial。したがってfactorial、パラメーターを渡せるように記述する必要があります。パラメーターを呼び出すと、コールバックに渡されます。次のようになります。

factorial (number, callback, params)
{
    result = number!   // i can make up operators in my pseudocode
    callback (result, params)
}

factorialこのパターンを許可すると、コールバックは次のようになります。

logIt (number, logger)
{
    logger.log(number)
}

そしてあなたの呼び出しfactorial

factorial(42, logIt, logger)

何かを返却したい場合はどうなりlogItますか?まあ、それはできません。なぜならfactorial、それに注意を払っていないからです。

さて、なぜfactorialコールバックが返すものを返すことができないのですか?

ノンブロッキングにする

実行はfactorial終了時にコールバックに渡されることを意図しているため、呼び出し側には何も返しません。そして理想的には、別のスレッド/プロセス/マシンで何らかの方法でその作業を開始し、すぐに戻って続行できるようにするでしょう。

factorial(param_1, param_2, ...)
{
    new factorial_worker_task(param_1, param_2, ...);
    return;
}

これは「非同期呼び出し」になりました。つまり、呼び出すとすぐに戻りますが、まだ実際には機能していません。したがって、それをチェックし、終了時に結果を取得するメカニズムが必要であり、プログラムはプロセスがより複雑になっています。

ちなみに、このパターンを使用factorial_worker_taskすると、コールバックを非同期で起動してすぐに戻ることができます。

それで、あなたは何をしますか?

答えは、コールバックパターン内に留まることです。いつでも書きたい

a = f()
g(a)

そしてf、あなたが代わりに書きます、非同期的に呼び出されます

f(g)

どこgコールバックとして渡されます。

これにより、プログラムのフロートポロジが根本的に変化し、慣れが必要になります。

プログラミング言語は、オンザフライで関数を作成する方法を提供することで、多くのことを支援することができます。すぐ上のコードでは、関数gはほど小さい場合がありますprint (2*a+1)。あなたの言語がこれを完全に不必要な名前とシグネチャを持つ別個の関数として定義することを要求するなら、あなたはこのパターンをたくさん使うとあなたの人生は不愉快になるでしょう。

一方、あなたの言語でラムダを作成できる場合は、はるかに良い状態です。その後、次のようなものを書くことになります

f( func(a) { print(2*a+1); })

それはとても良いです。

コールバックを渡す方法

どのようにコールバック関数を渡しますfactorialか?まあ、いくつかの方法でそれを行うことができます。

  1. 呼び出された関数が同じプロセスで実行されている場合、関数ポインタを渡すことができます

  2. またはfn name --> fn ptr、プログラムの辞書を維持したい場合は、名前を渡すことができます

  3. 多分あなたの言語はラムダとして可能な関数をその場で定義することを可能にします!内部的には、ある種のオブジェクトを作成し、ポインターを渡しますが、それについて心配する必要はありません。

  4. おそらく、呼び出す関数は完全に別のマシンで実行されており、HTTPなどのネットワークプロトコルを使用して呼び出します。コールバックをHTTP呼び出し可能な関数として公開し、そのURLを渡すことができます。

あなたはアイデアを得ます。

最近のコールバックの増加

私たちが参入したこのウェブ時代では、私たちが呼び出すサービスは、しばしばネットワーク上にあります。多くの場合、これらのサービスを制御することはできません。つまり、これらのサービスを記述しなかった、維持しなかった、サービスが稼働していること、またはサービスのパフォーマンスを確認できません。

しかし、これらのサービスが応答するのを待っている間、プログラムがブロックされることは期待できません。これを認識して、サービスプロバイダーはコールバックパターンを使用してAPIを設計することがよくあります。

JavaScriptは、ラムダやクロージャなどのコールバックを非常にうまくサポートしています。また、JavaScriptの世界には、ブラウザーとサーバーの両方で多くのアクティビティがあります。モバイル用に開発されているJavaScriptプラットフォームさえあります。

前進するにつれて、ますます多くの人が非同期コードを書くようになり、そのためにはこの理解が不可欠です。


1
コンセプトは非常によく説明されています。:)
piyushGoyal

すばらしい説明、+ 1。
リンガマーシーCS 2015

1
これは他のすべての中で最良の答えです。親切に賛成してください。
Abhishek Nalin 2016

3
完全に説明され、すべてが説明されています。私はそれをもう一度賛成できるといいのですが。
Yogesh Yadav 2016

はい、私はランバがJavaScriptとルビーでどのように機能するかを理解しています。Java 8ですが、Javaの古いバージョンはlambasを使用せず、代わりにクラスを使用していました。そのようなコールバックがどのように機能するか知りたいのですが。まだ他の優れた答え。
Donato

96

コールバックは1つの単語であることに注意してください。

ウィキペディアのコールバックページは、それを非常によく説明しています。

ウィキペディアのページからの引用:

コンピュータープログラミングでは、コールバックは実行可能コードまたは実行可能コードの一部への参照であり、引数として他のコードに渡されます。これにより、下位レベルのソフトウェアレイヤーが上位レベルのレイヤーで定義されたサブルーチン(または関数)を呼び出すことができます。


14
答えを提示するための素晴らしい方法。
チャトゥランガチャンドラセカラ

1
そして、これはまた別の方法で答えを導きます。「コールバック」という名詞は、「コールバック」されたものであり、シャットダウンを通過したものはシャットダウンされ、ログインに使用されるものはログインです。
匿名

22
これはコメントだったかもしれません-基本的にはWikipediaへのリンクです
CodyBugstein

ウィキペディアには、実際にすばらしいプログラミング機能がいくつかあります。「コールバック」という言葉は「コールバックするつもりです...」というフレーズを使って最もよく説明されているようにいつも感じていました
Thomas

javascriptissexy.com/…でのすばらしい説明 ここで再投稿します。コールバック関数は、パラメーターとして別の関数に渡される関数であり、コールバック関数は、otherFunction内で呼び出されるか実行されます。//クリックメソッドのパラメータの項目は変数ではなく関数であることに注意してください。//項目はコールバック関数です$( "#btn_1")。click(function(){alert( "Btn 1 Clicked" );}); 前の例にあるように、関数をパラメーターとしてクリックメソッドに
渡し

46

素人の反応は、特定のイベントが発生した後、またはコードが処理された後に、ユーザーではなくブラウザによって呼び出される関数であるということです。


42

コールバック関数は、特定の条件が満たされたときに呼び出される関数です。コールバック関数はすぐに呼び出されるのではなく、将来のある時点で呼び出されます。

通常、非同期で終了する(つまり、呼び出し元の関数が戻った後しばらくすると終了する)タスクが開始されるときに使用されます。

たとえば、ウェブページをリクエストする関数では、ウェブページのダウンロードが完了したときに呼び出されるコールバック関数を呼び出し元に提供する必要があります。


最初の文では、あなたは言う"...when a condition is met"が、親関数の実行が終了し、条件(?)に依存しないときにコールバックが呼び出されると思いました。
Ojonugwa Jude Ochalifu 2014

「特定の条件」とは、ランダムではなく、通常、理由によって呼び出されることを意味します。親/作成者がまだ実行しているときにコールバックを呼び出すことができます。これは、プログラマーが予期していない場合に、競合状態を引き起こす可能性があります。
Thomas Bratt 2014

わかりました。説明を
ありがとう

34

コールバックは、電話システムの観点から最も簡単に説明できます。関数呼び出しは、電話で誰かに電話をかけ、質問をし、回答を得て、電話を切るのに似ています。コールバックを追加すると、アナロジーが変更され、彼女に質問した後、彼女に名前と番号を与えて、彼女があなたに電話で返答できるようにします。

-Paul Jakubik、「C ++でのコールバック実装」


1
私の名前と番号は関数ですか?
Koray Tugay

いいえ、代わりに「コールバック」が適切な名前だったとすれば、電話オペレーターに電話をかけるように依頼するのと同じです。終わり。
ガーソン

33

この「コールバック」専門用語は、多くの場所で誤って使用されていると思います。私の定義は次のようになります:

コールバック関数は、誰かに渡し、ある時点で呼び出せるようにする関数です。

私は人々がウィキ定義の最初の文を読んだだけだと思います:

コールバックは、他のコードへの引数として渡される実行可能コードまたは実行可能コードの一部への参照です。

私は多くのAPIを扱ってきました。さまざまな悪い例を参照してください。多くの人は、関数ポインター(実行可能コードへの参照)または匿名関数(実行可能コードの一部)に「コールバック」という名前を付ける傾向があります。これらが単なる関数であれば、なぜ別の名前が必要なのですか?

実際には、wiki定義の2番目の文だけが、コールバック関数と通常の関数の違いを明らかにしています。

これにより、下位レベルのソフトウェアレイヤーが上位レベルのレイヤーで定義されたサブルーチン(または関数)を呼び出すことができます。

そのため、違いは、関数を渡すのはだれであり、渡された関数がどのように呼び出されるかです。関数を定義して別の関数に渡し、その関数本体で直接呼び出す場合は、コールバックと呼ばないでください。定義によると、渡された関数は「下位レベル」の関数から呼び出されます。

あいまいな状況でこの単語の使用をやめてほしいと思います。理解を深めるのに役立ちません。


2
あなたの答えは理にかなっています...しかし、私はそれを描くのに苦労しています。例を挙げていただけますか?
CodyBugstein

3
@Zane Wong ::最後に、「定義では、渡された関数は「下位レベル」の関数から呼び出される」と書いています。下位レベルの機能が何を示しているか説明していただけますか?あなたが例を挙げればそれはより良いです。
Viku

例はいいでしょう
Yousuf Azad

1
古典的な関数呼び出しとコールバックスタイルの違いは、依存する方向へのリンクにあると思います。モジュールAがモジュールBに依存する(「使用する」)場合、AはBの関数を呼び出し、それはコールバックではありません。Aが自分の関数への参照をBに渡すと、BはAの関数を呼び出します。これはコールバックです。呼び出しは、モジュールの依存関係と比較して逆方向に進みます。
XouDo

30

シンプルにしましょう。コールバック機能とは?

たとえ話と類推による例

秘書がいます。毎日私は彼女に次のことを求めます:(i)会社の郵便を郵便局に送り、それが終わったら次のようにします:(ii)付箋の 1つに彼女のために書いたタスク。

さて、付箋のタスクは何ですか?タスクは日々異なります。

この特定の日に、私は彼女にいくつかの文書を印刷するように要求するとします。それを付箋に書いて、彼女が投稿する必要がある送信メールと一緒に彼女の机にそれをピンで留めます。

要約すれば:

  1. 最初に、彼女は郵便を降ろす必要があり、
  2. それが行われた直後に、彼女はいくつかの文書を印刷する必要があります。

コールバック関数は、その2番目のタスクである、それらのドキュメントの印刷です。これは、メールがドロップされた後に行われるため、また、ドキュメントを印刷するように彼女に通知する付箋が、彼女が投稿する必要のあるメールと共に彼女に与えられるからです。

これをプログラミング語彙と結び付けましょう

  • この場合のメソッド名は、DropOffMailです。
  • また、コールバック関数はPrintOffDocumentsです。PrintOffDocumentsはコールバック関数です。これは、DropOffMailが実行された後でのみ、秘書にそれを実行させるためです。
  • そのため、私は「パス:PrintOffDocumentsをDropOffMailメソッドへの「引数」として渡します。これは重要なポイントです。

それだけです。これ以上何もない。私はそれがあなたのためにクリアされたことを願っています-そうでない場合は、コメントを投稿してください。明確にするために最善を尽くします。


18

これにより、コールバックはメソッドの最後のreturnステートメントのように聞こえます。

それが何であるかはわかりません。

コールバックは、別の関数が呼び出されて完了した結果として、実際には関数の呼び出しであると思います。

私はまた、コールバックは、「ちょっと!あなたが求めたものですか?私はそれをやった-ちょうどあなたに知らせたいと思った-あなたに戻って」というような形で、元の呼び出しに対処することを意図しているとも思います。


1
+1は、コールバックとリターンのステートメントに質問します。私はこれに夢中になっていたので、一緒に働いている多くの卒業生もそうです。
8bitjunkie 2011

2
良い回答-他の多くの回答とは異なり、理解に役立ちました。
adaam 2014年

18

コールバックとは何ですか?

  • 一般に、誰かが受け取ったものを返すために行われる電話。
  • コンピューティングでは、コールバックは、他のコードに引数として渡される実行可能コードの一部です。関数がその作業を完了すると(または何らかのイベントが発生したとき)、コールバック(コールバック、つまり名前)関数が呼び出されます。

コールバック関数とは何ですか?

  • コールバック関数は、タスクを完了したときにマスターに「コールバック」するサーバントのようなものです。
  • コールバック関数は(聞かせてのは、この他の関数を呼び出す別の関数に渡される関数であるotherFunctionパラメータとして)、およびコールバック関数が呼び出される(または実行)される内部otherFunction
    function action(x, y, callback) {
        return callback(x, y);
    }

    function multiplication(x, y) {
        return x * y;
    }

    function addition(x, y) {
        return x + y;
    }

    alert(action(10, 10, multiplication)); // output: 100

    alert(action(10, 10, addition)); // output: 20

SOAでは、コールバックにより、プラグインモジュールはコンテナー/環境からサービスにアクセスできます。

類推:コールバック。非同期。コールバックのノンブロッキング
リアルライフの例


コールバック関数自体は高階関数ではありません。高次関数に渡されます。
danio 2016年

17

Call Afterは、愚かな名前であるcallbackよりも良い名前です。関数内で条件が満たされた場合、または条件が満たされた場合は、引数として受け取った別の関数Call After関数を呼び出します。

関数内の内部関数をハードコードするのではなく、すでに記述されたCall After関数を引数として受け入れる関数を記述します。呼び出しは、引数を受け取る関数のコードによって検出された状態変化に基づいて呼び出される場合があります。


これは素晴らしいアイデアです。私はこれを説明するために「後ろに呼ばれた」に行きました。マーティンファウラーのような誰かが彼の独創的なブログでこれらの新しい用語として「コールアフター」を大衆化するのを見ることができました。
8bitjunkie 2016年

15

コールバック関数は、既存の関数/メソッドに指定する関数で、アクションが完了したときに呼び出されたり、追加の処理が必要になったりします。

たとえばJavaScript、より具体的にはjQueryでは、アニメーションが終了したときに呼び出されるコールバック引数を指定できます。

PHPでは、このpreg_replace_callback()関数を使用して、正規表現が一致したときに呼び出される関数を提供し、一致した文字列を引数として渡すことができます。


10

画像を見てください:)これがどのように機能するか

メインプログラムは、コールバック関数名を使用してライブラリ関数(システムレベルの関数の場合もあります)を呼び出します。このコールバック関数は、複数の方法で実装される場合があります。メインプログラムは、要件に従ってコールバックを1つ選択します。

最後に、ライブラリ関数は実行中にコールバック関数を呼び出します。


7
これにテキストの説明を追加してもよろしいですか?画像が消えると、この答えはすべてのコンテキストを失います。
Tim Post

他の人からのテキストがそれを最もよく説明しています。私が欠けていると感じたのは画像だけです:)

ここで私が見た長い説明の中で、これは私を「ああ、今、私はその使用法を理解した」のです。賛成票を持っています。
DiBosco

7

この質問に対する簡単な答えは、コールバック関数は関数ポインターを介して呼び出される関数であるということです。関数のポインター(アドレス)を引数として別の関数に渡す場合、そのポインターが関数の呼び出しに使用されると、そのポインターが指すポインターは、コールバックが行われたと見なされます。


6

我々は機能があると仮定しsort(int *arraytobesorted,void (*algorithmchosen)(void))、それが中にいくつかの点で使用することができ、引数として関数ポインタを受け付けることができるsort()の実装を。次に、関数ポインタによってアドレス指定されているコードがコールバック関数algorithmchosenとして呼び出されます

また、次のようなアルゴリズムを選択できるという利点もあります。

  1.    algorithmchosen = bubblesort
  2.    algorithmchosen = heapsort
  3.    algorithmchosen = mergesort   ...

これは、たとえば、プロトタイプで実装されています。

  1.   `void bubblesort(void)`
  2.   `void heapsort(void)`
  3.   `void mergesort(void)`   ...

これは、オブジェクト指向プログラミングでポリモーフィズムを実現するために使用される概念です。


javascriptissexy.com/…でのすばらしい説明 ここで再投稿します。コールバック関数は、パラメーターとして別の関数に渡される関数であり、コールバック関数は、otherFunction内で呼び出されるか実行されます。//クリックメソッドのパラメータの項目は変数ではなく関数であることに注意してください。//項目はコールバック関数です$( "#btn_1")。click(function(){alert( "Btn 1 Clicked" );}); 前の例でわかるように、関数をパラメーターとしてクリックメソッドに
渡し

4

「コンピュータープログラミングでは、コールバックは実行可能コードまたは実行可能コードの一部への参照であり、引数として他のコードに渡されます。これにより、下位レベルのソフトウェアレイヤーは、上位レベルのレイヤーで定義されたサブルーチン(または関数)を呼び出すことができます。」-ウィキペディア

関数ポインターを使用したCでのコールバック

Cでは、コールバックは関数ポインターを使用して実装されます。関数ポインタ-名前が示すように、関数へのポインタです。

たとえば、int(* ptrFunc)();

ここで、ptrFuncは、引数を取らず整数を返す関数へのポインターです。括弧を入れることを忘れないでください。そうしないと、コンパイラーは、ptrFuncが通常の関数名であると想定します。これは、何も取らず、整数へのポインターを返します。

以下は、関数ポインターを示すコードです。

#include<stdio.h>
int func(int, int);
int main(void)
{
    int result1,result2;
    /* declaring a pointer to a function which takes
       two int arguments and returns an integer as result */
    int (*ptrFunc)(int,int);

    /* assigning ptrFunc to func's address */                    
    ptrFunc=func;

    /* calling func() through explicit dereference */
    result1 = (*ptrFunc)(10,20);

    /* calling func() through implicit dereference */        
    result2 = ptrFunc(10,20);            
    printf("result1 = %d result2 = %d\n",result1,result2);
    return 0;
}

int func(int x, int y)
{
    return x+y;
}

ここで、関数ポインターを使用してCでのコールバックの概念を理解してみましょう。

完全なプログラムには、callback.c、reg_callback.h、およびreg_callback.cの3つのファイルがあります。

/* callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}

int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                        
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                          
    printf("back inside main program\n");
    return 0;
}

/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);


/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                               
}

このプログラムを実行すると、出力は次のようになります

これは、my_callback内のregister_callback内の関数コールバックをメインプログラム内に示すプログラムです。

上位層関数は下位層関数を通常の呼び出しとして呼び出し、コールバックメカニズムにより、下位層関数はコールバック関数へのポインターを介して上位層関数を呼び出すことができます。

インターフェースを使用したJavaでのコールバック

Javaには関数ポインターの概念がありません。これは、そのインターフェイスメカニズムを介してコールバックメカニズムを実装します。ここでは、関数ポインターの代わりに、呼び出し先がタスクを完了すると呼び出されるメソッドを持つインターフェイスを宣言します。

例を挙げて説明します。

コールバックインターフェイス

public interface Callback
{
    public void notify(Result result);
}

呼び出し元または上位クラス

public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}

呼び出し先または下位層関数

public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}

doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}

EventListenerパターンを使用したコールバック

  • リストアイテム

このパターンは、特定のタスクが終了したことを0〜n個のオブザーバー/リスナーに通知するために使用されます

  • リストアイテム

CallbackメカニズムとEventListener / Observerメカニズムの違いは、コールバックでは呼び出し先が単一の呼び出し元に通知するのに対し、Eventlisener / Observerでは呼び出し先はそのイベントに関心のある誰にでも通知できることです(通知は、タスクをトリガーしていないアプリケーション)

例を挙げて説明します。

イベントインターフェース

public interface Events {

public void clickEvent();
public void longClickEvent();
}

クラスウィジェット

package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}

クラスボタン

public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}

クラスチェックボックス

public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}

活動クラス

パッケージcom.som_itsolutions.training.java.exampleeventlistener;

public class Activity implements Widget.OnClickEventListener
{
    public Button mButton;
    public CheckBox mCheckBox;
    private static Activity mActivityHandler;
    public static Activity getActivityHandle(){
        return mActivityHandler;
    }
    public Activity ()
    {
        mActivityHandler = this;
        mButton = new Button();
        mButton.setOnClickEventListner(this);
        mCheckBox = new CheckBox();
        mCheckBox.setOnClickEventListner(this);
        } 
    public void onClick (Widget source)
    {
        if(source == mButton){
            mButton.setButtonText("Thank you for clicking me...");
            System.out.println(((Button) mButton).getButtonText());
        }
        if(source == mCheckBox){
            if(mCheckBox.isChecked()==false){
                mCheckBox.setCheck(true);
                System.out.println("The checkbox is checked...");
            }
            else{
                mCheckBox.setCheck(false);
                System.out.println("The checkbox is not checked...");
            }       
        }
    }
    public void doSomeWork(Widget source){
        source.clickEvent();
    }   
}

他のクラス

public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event                        //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}

メインクラス

public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}

上記のコードからわかるように、アプリケーションで発生する可能性のあるすべてのイベントを基本的にリストする、eventsというインターフェイスがあります。Widgetクラスは、Button、CheckboxなどのすべてのUIコンポーネントの基本クラスです。これらのUIコンポーネントは、フレームワークコードから実際にイベントを受け取るオブジェクトです。Widgetクラスは、Eventsインターフェイスを実装し、OnClickEventListenerとOnLongClickEventListenerの2つのネストされたインターフェイスも持っています

これら2つのインターフェースは、ボタンやチェックボックスなどのウィジェット派生UIコンポーネントで発生する可能性のあるイベントをリッスンします。したがって、この例をJavaインターフェースを使用した以前のコールバックの例と比較すると、これら2つのインターフェースはコールバックインターフェースとして機能します。したがって、上位レベルのコード(Here Activity)はこれら2つのインターフェースを実装します。また、ウィジェットに対してイベントが発生すると、上位レベルのコード(または上位レベルのコードに実装されたこれらのインターフェースのメソッド、ここではActivity)が呼び出されます。

次に、コールバックパターンとイベントリスナーパターンの基本的な違いについて説明します。コールバックを使用すると説明したように、呼び出し先は単一の呼び出し元にのみ通知できます。ただし、EventListenerパターンの場合、アプリケーションの他の部分またはクラスは、ボタンまたはチェックボックスで発生する可能性のあるイベントに登録できます。この種のクラスの例は、OtherClassです。OtherClassのコードが表示されている場合、アクティビティで定義されたボタンで発生する可能性のあるClickEventのリスナーとして登録されていることがわかります。興味深い点は、アクティビティ(呼び出し元)の他に、ボタンでクリックイベントが発生するたびに、このOtherClassにも通知が送られることです。


回答のみのリンクは避けてください。「外部サイトへのリンク以上のものではない」という回答は削除される場合があります
Quentin

3

コールバック関数は、特定の関数またはオブジェクトに(参照またはポインターとして)渡す関数です。この関数またはオブジェクトは、いつでも、場合によっては複数回、この関数を任意の種類の目的で呼び出します。

  • タスクの終了を通知する
  • 2つの項目間の比較を要求する(c qsort()など)
  • プロセスの進捗状況を報告する
  • 通知イベント
  • オブジェクトのインスタンス化を委任する
  • エリアの絵を委任する

...

したがって、コールバックを別の関数またはタスクの最後に呼び出される関数として説明することは、(それが一般的なユースケースであっても)過度に単純化されます。


2

コールバックは、関数をパラメーターとして別の関数に渡し、プロセスが完了すると呼び出されるようにするアイデアです。

上記の素晴らしい答えからコールバックの概念を理解できたら、そのアイデアの背景を学ぶことをお勧めします。

「彼ら(コンピュータ科学者)がコールバックを開発したのはなぜですか?」あなたはブロッキングという問題を学ぶかもしれません。(特にブロッキングUI)そしてコールバックがそれに対する唯一のソリューションではありません。他の多くのソリューションがあります(例:スレッド、先物、約束...)。


1

重要な使用領域の1つは、関数の1つをハンドル(つまり、コールバック)として登録し、メッセージを送信するか、関数を呼び出して、いくつかの作業または処理を行うことです。これで処理が完了すると、呼び出された関数が登録された関数を呼び出し(つまり、コールバックが行われる)、処理が完了したことが示されます。
このウィキペディアのリンクは、グラフィックでかなりよく説明されています。


1

高次関数とも呼ばれるコールバック関数は、パラメーターとして別の関数に渡される関数であり、コールバック関数は親関数内で呼び出されます(または実行されます)。

$("#button_1").click(function() {
  alert("button 1 Clicked");
});

ここでは、関数をパラメーターとしてクリックメソッドに渡します。そして、クリックメソッドは、渡されたコールバック関数を呼び出し(または実行)します。


1
コールバック関数自体は高階関数ではありません。高次関数に渡されます。
danio 2016年

1

コールバック関数 引数として別の関数に渡された関数。

function test_function(){       
 alert("Hello world");  
} 

setTimeout(test_function, 2000);

注:上記の例では、setTimeout関数の引数としてtest_functionを使用しています。


1
Stack Overflowへようこそ!質問に回答する前に、必ず既存の回答を読んでください。この回答はすでに提供されています。答えを繰り返す代わりに、既存の答えに投票してください。良い答えを書くためのいくつかのガイドラインはここにあります
dferenc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.