Usage Guide: Persistent Callbacks
By default, a callback function passed between Java and JavaScript is designed for a single use. After it's invoked once, it is removed from memory to prevent leaks. However, some scenarios require a long-lasting communication channel where one side can send multiple messages to the other over time.
Persistent callbacks solve this problem. They are not discarded after the first use and can be invoked multiple times.
This is useful for:
- Real-time data updates (e.g., streaming sensor data to the UI).
- Event notifications (e.g., native download progress updates).
- Maintaining a long-term communication link without re-establishing it.
Java Calling JavaScript with a Persistent Callback
When you want JavaScript to be able to call back to your Java code multiple times, use callHandlerPersistent
.
Java Side
// Use callHandlerPersistent to create a callback that won't be deleted.
webView.callHandlerPersistent("startListeningToEvents", "some-event-id", new OnBridgeCallback() {
@Override
public void onCallBack(String data) {
// This callback can be invoked multiple times from JavaScript.
Log.d(TAG, "Persistent callback in Java called with: " + data);
// Update UI or perform action based on the event data.
}
});
JavaScript Side
In JavaScript, the handler receives the responseCallback
as usual. The difference is that this callback can now be stored and reused.
var eventCallback = null; // Variable to store the persistent callback
bridge.registerHandler("startListeningToEvents", function(data, responseCallback) {
console.log("Java wants to listen to events with ID: " + data);
// Store the callback for later use
eventCallback = responseCallback;
// Send an initial confirmation
eventCallback("Listening has started.");
});
// Later, when an event occurs, you can reuse the stored callback
document.getElementById('some-button').onclick = function() {
if (eventCallback) {
eventCallback("An event just happened!");
}
};
JavaScript Calling Java with a Persistent Callback
The pattern is similar when the communication originates from JavaScript.
JavaScript Side
// Use callHandlerPersistent to keep the JS callback active.
WebViewJavascriptBridge.callHandlerPersistent("javaProgressHandler", { 'taskId': 123 }, function(response) {
// This callback can be invoked multiple times from Java.
console.log("Progress update from Java: " + response);
});
Java Side
Your Java handler will receive an OnBridgeCallback
function. You must store this function's unique callbackId
to send responses back later.
This is typically managed by adding a JavascriptInterface
, as seen in the example
app's MainJavascriptInterface.java
.
// A simplified conceptual example
public class MyHandlers {
private OnBridgeCallback progressCallback;
public void registerProgressHandler() {
webView.registerHandler("javaProgressHandler", new BridgeHandler() {
@Override
public void handler(String data, OnBridgeCallback function) {
// Store the callback for later use
progressCallback = function;
// Send initial confirmation
progressCallback.onCallBack("Progress tracking started.");
}
});
}
// When progress happens elsewhere in your app...
public void updateProgress(int progress) {
if (progressCallback != null) {
progressCallback.onCallBack("Progress is now " + progress + "%");
}
}
}
Manual Management (JavaScript)
JavaScript also provides functions to manually register and remove persistent callbacks if you need finer control over their lifecycle.
// Manually register a persistent callback with a custom ID
var callbackId = "my_persistent_callback";
WebViewJavascriptBridge.registerPersistentCallback(callbackId, function(data) {
console.log("Persistent callback '" + callbackId + "' called with: ", data);
});
// When you are done with it, remove it to prevent memory leaks
WebViewJavascriptBridge.removePersistentCallback(callbackId);