Callbacks are defined in Wikipedia as:
In computer programming, a callback function refers to a reference to a certain piece of executable code that is passed to other code through function parameters.
The purpose is to allow the underlying code to call subroutines defined at the higher level.
For example, it may be more clear: Taking the use of retrofit for network requests in Android as an example, this is an example of asynchronous callbacks.
After initiating a network request, the app can continue other things. The result of the network request is generally obtained through the two methods of onResponse and onFailure. Take a look at the code in the relevant part:
(new Callback<HistoryBean>() { @Override public void onResponse(Call<HistoryBean> call, Response<HistoryBean> response) { HistoryBean hb = (); if(hb == null) return; (() + ""); for( rb : ()){ (() + "/n"); } } @Override public void onFailure(Call<HistoryBean> call, Throwable t) { } });
Ignore the generics in CallBack above. According to the definition in Wikipedia, all the code in the anonymous internal class can be viewed asA reference to a certain executable code that is passed to other code. The two methods onResponse and onFailure are callback methods. The underlying code is the unchanged network request part that has been written, and the subroutine defined by the higher level is the callback. Because the specific implementation is handed over to the user, it has high flexibility. The above is related through the method enqueue (Callback callback).
Steps of callback method
The callback mentioned above is a very common concept. If you put it in the program writing, you can say:
In Class A, a method C in Class B is called, and then in Class B, method D in Class A is called in reverse. D is the callback method. Class B is the underlying code, and Class A is the high-level code.
So through the above explanation, we can infer something. In order to represent the universality of method D, we use the interface form to make method D called an interface method. If Class B wants to call method D in Class A, then Class A must implement this interface. In this way, depending on the implementation, there will be polymorphism, making the method flexible.
If Class A wants to call a method C in Class B, then Class A must contain a reference to B, otherwise it will not be called. This step is called the registration callback interface. So how to implement the reverse call method D in Class A in Class B, directly through the above method C. Method C in Class B accepts an interface type parameter. Then, only in method C, you need to use the parameters of this interface type to call method D in class B, which in turn calls method D in Class A. This step is called calling the callback interface.
This also implements that in the C method of Class B, the D method in Class A needs to be called in reverse, which is the callback. A calls B to directly tune, which can be regarded as using the underlying API for high-level code. We often write programs like this. B calls A to call back, and the underlying API requires high-level code to execute.
Finally, let’s summarize the steps of the callback method:
- Class A implement interface CallBack callback
- Class A contains a reference to B
- There is a method f(CallBack callback) in B with the parameter CallBack
- Call B's method f(CallBack callback) in Class A - Register the callback interface
- B can call A's method in f(CallBack callback) method-called callback interface
Callback example
Let’s take a son playing games and waiting for his mother to prepare the meal and notify his son to come and eat as an example, and follow the above steps to write a callback;
In the above example, it is obvious that the son should implement the callback interface and the mother should call the callback interface. So we first define a callback interface, and then let our son implement this callback interface.
The code is as follows:
public interface CallBack { void eat(); }
public class Son implements CallBack{ private Mom mom; //Class A holds a reference to Class B public void setMom(Mom mom){ = mom; } @Override public void eat() { ("I'm here to have a meal"); } public void askMom(){ //Call methods containing interface parameters through references of Class B. ("Have you cooked the meal?"); ("I haven't done it well, I've played the game"); new Thread(() -> ()).start(); ("It's been playing the game..."); } }
Then we also need to define a mother's class, which contains a method doCook with interface parameters
public class Mom { //Call the callback method using interface parameters in a method containing interface parameters public void doCook(CallBack callBack){ new Thread(new Runnable() { @Override public void run() { try { ("Cooking..."); (5000); (); } catch (InterruptedException e) { (); } } }).start(); } }
We pass a test class:
public class Test { public static void main(String[] args) { Mom mom = new Mom(); Son son = new Son(); (mom); (); } }
This example is a typical callback example. The Son class implements the interface callback method. Through the askMom method, the doCook in the Mom class is called to implement the registration callback interface, which is equivalent to the code C of calling Class B in Class A. DoCook in Mom class calls back and forth the eat in the Son class to tell the results in the Son class.
In this way, we implement a simple, defined callback.
Further exploration of callback examples
Let's mainly look at the code of the Son class:
public class Son implements CallBack{ public Mom mom; public Son(Mom mom){ = mom; } public void askMom(){ ("Have you cooked the meal?"); ("I haven't done it well, I've played the game"); new Thread(() -> ()).start(); ("It's been playing the game..."); } @Override public void eat() { ("Okay, I'm here to have a meal"); } }
In this class, in addition to outputting some statements, the really useful parts are () and rewriting the eat method. Therefore, we can abbreviate this callback through the form of anonymous inner class. The code is as follows:
public class CallBackTest { public static void main(String[] args) { Mom mom = new Mom(); new Thread(()-> (() -> ("It's time to eat..."))).start(); } }
Cancel the Son class and directly implement the eat method through anonymous inner class in the main method. In fact, anonymous internal classes are the embodiment of callbacks.
Asynchronous callbacks and synchronous callbacks
Callback mentioned above: A calls method C in class B, and then calls method D in class A through class A objects in method C.
Let's talk about asynchronous and synchronization, let's talk about the concept of synchronization first.
synchronous
Synchronization means that when calling a method, if the previous method call is not executed, a new method call cannot be made. In other words, things must be done one by one, and you can only do the next one after another.
asynchronous
Asynchronousness is relative to synchronization, you don’t need to wait until the previous method call is finished before calling a new method. Therefore, in asynchronous method calls, a method is needed to notify the user of the method call result.
Implement asynchronous methods
The most common way to implement asynchronous in Java is to let the method you want to execute asynchronously in a new thread.
We will find that a method is needed in an asynchronous method call to notify the user's call result. Based on the above, we will find that the callback method is suitable for doing this, and notify the user of the call result through the callback method.
The asynchronous callback is done in a new thread when A calls B's method C.
The above example of the mother notifying her son for dinner is an example of an asynchronous callback. In a new thread, the doCook method is called and the return value is finally accepted through eat. Of course, after using lamdba optimization, the essence is the same.
Synchronous callback means that A calls B method C not in a new thread. When executing this method C, we can do nothing and can only wait for it to complete.
Examples of synchronous callbacks and asynchronous callbacks
Let's look at an example of a synchronous callback in Android:
(new () { @Override public void onClick(View v) { ("button","Clicked"); } });
button bysetOnClickListenerRegister the callback function, as written above, pass the reference to the interface in the form of an anonymous internal class. Since the button calls setOnClickListener without creating a new thread, this is a synchronous callback.
Asynchronous callback is the example we talked about at the beginning:
(new Callback<HistoryBean>() { @Override public void onResponse(Call<HistoryBean> call, Response<HistoryBean> response) { HistoryBean hb = (); if(hb == null) return; (() + ""); for( rb : ()){ (() + "/n"); } } @Override public void onFailure(Call<HistoryBean> call, Throwable t) { } });
This enqueue method is an asynchronous method to request remote network data. When it is implemented internally, it is executed through a new thread.
Through these two examples, we can see that the use of synchronous callbacks and asynchronous callbacks is actually designed according to different needs. It cannot be said that one replaces the other. For example, in the button click event above, if it is an asynchronous callback, the click effect does not appear immediately after the user clicks the button, and the user will not perform other operations, it will feel strange. Asynchronous callbacks for network requests, because the requested resource may not exist, network connection is unstable, and other reasons, the user is not clear about the execution of the method, so they will use asynchronous callbacks, initiate the method call and do other things, and then wait for the callback notification.
Application of callback method in communication
The callback methods mentioned above, except for the callbacks of the network request framework, all have no parameters. Let’s take a look at adding parameters to the callback method to implement some communication problems.
If we want Class A to obtain Class B’s data after a series of calculations and processing, and the two classes cannot simply refer to Class A’s data. We can consider callbacks.
The steps are as follows:
- Write a callback interface in the class that has the data. -->This is a callback interface written in Class B
- The callback method receives a parameter, which is the data to be obtained.
- Also, write a method to register a callback in this class.
- When registering a callback method, use the reference of the interface to call the callback interface, and pass the B class data into the callback method as a parameter.
- In Class A, use the reference of Class B to register the callback interface and pass the data in Class B to Class A through the callback.
The steps mentioned above are a bit abstract. Let’s look at an example below, one is Client and the other is Server. Client requests the server's time-consuming data processed.
public class Client{ public Server server; public String request; //Link Server and get the Server reference. public Client connect(Server server){ = server; return this; } //Client, set request public Client setRequest(String request){ = request; return this; } //Asynchronously sending requests, lambda expressions. public void enqueue( callBack){ new Thread(()->(request,callBack)).start(); } }
public class Server { public String response = "This is an html"; //Register the callback interface method and pass the data to the callback interface through parameters public void setCallBack(String request,CallBack callBack){ ("A request has been received and is being calculated..."); new Thread(() -> { try { (5000); (request + response); } catch (InterruptedException e) { (); (e); } }).start(); } // Write an interface in the class that has the data public interface CallBack{ void onResponse(String response); void onFail(Throwable throwable); } }
Next, let's take a look at the test example:
public class CallBackTest { public static void main(String[] args) { Client client = new Client(); (new Server()).setRequest("What is this file?").enqueue(new () { @Override public void onResponse(String response) { (response); } @Override public void onFail(Throwable throwable) { (()); } }); } }
The results are as follows:
Already receivedrequest,In calculation...... What is this file?This is ahtml
The above is to communicate through callbacks.
The above is all the content of this article. I hope that the content of this article will help you study or work. I also hope to support me more!