Last week I started a series of articles regarding Android Module Development. Toady I am going to continue with next topic which is Using event listeners and callbacks in Module
During asynchronous operation, if we want to pass the data to javascript layer we have to use callbacks. It will call the particular method to send the data back to javascript layer. For example like onError, onSuccess. Callback will be invoked only once.
Example
Lets consider AudioRecorder module here I am using success and error callbacks, which will be called either on success or failure of audio recording process. It will be invoked only once.
In Module
For more detail refer AudioRecorder module source code and this blog post- Understanding methods, properties, constants and module life cycle
- Using event listeners and callbacks in Module
- Converting native control into Titanium view
- Accessing module and app resources
- Using XML layouts in modules
During asynchronous operation, if we want to pass the data to javascript layer we have to use callbacks. It will call the particular method to send the data back to javascript layer. For example like onError, onSuccess. Callback will be invoked only once.
Example
Lets consider AudioRecorder module here I am using success and error callbacks, which will be called either on success or failure of audio recording process. It will be invoked only once.
In Module
// initializing callbacks private KrollFunction successCallback = null; private KrollFunction errorCallback = null; // method to invoke success callback private void sendSuccessEvent(String filepath) { if (successCallback != null) { HashMap event = new HashMap(); event.put("filePath", filepath); event.put("fileName", outPutFileName); // Fire an event directly to the specified listener (callback) successCallback.call(getKrollObject(), event); } } // method to invoke error callback private void sendErrorEvent(String message) { if (errorCallback != null) { HashMap event = new HashMap(); event.put("message", message); // Fire an event directly to the specified listener (callback) errorCallback.call(getKrollObject(), event); } } // method to register callbacks, which all passed from javascript layer @Kroll.method public void registerCallbacks(HashMap args) { Object callback; // Save the callback functions, verifying that they are of the correct // type if (args.containsKey("success")) { callback = args.get("success"); if (callback instanceof KrollFunction) { successCallback = (KrollFunction) callback; } } if (args.containsKey("error")) { callback = args.get("error"); if (callback instanceof KrollFunction) { errorCallback = (KrollFunction) callback; } } } @Kroll.method public void startRecording(HashMap args) { if (isRecording) { // calling sendErrorEvent to invoke error callback sendErrorEvent("Another audio record is inprogress"); } else { recorder = null; // this method used to register success and error callbacks registerCallbacks(args); recorder = new MediaRecorder(); recorder.setOutputFile(outputFileName); recorder.setOnErrorListener(errorListener); recorder.setOnInfoListener(infoListener); try { recorder.prepare(); recorder.start(); isRecording = true; } catch (IllegalStateException e) { System.out.println("@@## Error1 e = " + e); e.printStackTrace(); isRecording = false; // calling sendErrorEvent to invoke error callback sendErrorEvent(e.toString()); } catch (IOException e) { e.printStackTrace(); System.out.println("@@## Error3 e = " + e); isRecording = false; // calling sendErrorEvent to invoke error callback sendErrorEvent(e.toString()); } } }In Javascript
var audioRecorder = require("titutorial.audiorecorder"); audioRecorder.startRecording({ outputFormat: audioRecorder.OutputFormat_THREE_GPP, audioEncoder: audioRecorder.AudioEncoder_AMR_NB, directoryName: "testdir", fileName: "testfile", maxFileSize: 7000, success: function (e) { alert("success => " + e.filePath); }, error: function (d) { alert("error => " + e.message); } });
Event listeners
Registered event listeners will be called whenever the event occur.
Example
Lets consider Ratingbar module here when user change the rating, the new rating value passed to javascript layer via event listener. It may fired so many times.
In Module
private boolean hasListenerChange = false; //checks whether "change" event listener added to proxy or not hasListenerChange = proxy.hasListeners("change"); ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() { @SuppressWarnings("deprecation") public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) { //if listener added to proxy, it pass the data to javascript layer if (hasListenerChange) { KrollDict props = new KrollDict(); props.put("rating", rating); //fires the change event proxy.fireEvent("change", props); } } });In Javascript
var ratingbarProxy = require('titutorial.ratingbar'); var ratingBar = ratingbarProxy.createRatingBar({ top : '30dp', left:15, rating : 2, stars : 6, stepSize : 1.5, isIndicator : false }); win.add(ratingBar); ratingBar.addEventListener('change', function(e) { ratingValue.text = "Rating Value : "+e.rating.toString(); });
For more detailed example refer Ratingbar module source code
Continue with part 3
Great work with these tutorials!
ReplyDeleteI am very new to creating android modules and am trying something out so that i can use bluetooth: My question is when you have an \Activity how do you send back the result to the application? The scenario is as follow:
I have BluetoothModule:
@Kroll.method
public void startBluetooth(){
Activity activity = TiApplication.getAppCurrentActivity();
activity.startActivity(new Intent("com.test.bt2.BLUETOOTH"));
}
I have setup the TiModule.xml to communicate with the activity and in Bluetooth class which extends Activity i have an on create method which checks if bluetooth is enabled:
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
together with that I have the onActivityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (resultCode == RESULT_OK){
Log.i(LCAT, "Connected");
} else {
Log.e(LCAT, "Something went wrong");
}
}
The thing is i have no clue on how the result from the activityResult is pushed back to Titanium? How would you go about it? thanks
Hi Michael,
ReplyDeleteFFor that you have to implement the TiActivityResultHandler interface and launchActivityForResult (instead of startActivityForResult ) here you can find the clear example https://bitbucket.org/prakashmcam/voice2textmodule/src/8901e4ead35504eda9ca499b4708ecc07a4dc007/src/learappcelerator/voice2text/Voice2textModule.java?at=master
let me know if have anymore questions.
Brilliant, thanks it worked perfectly . Keep up the good work with these tutorials as they are really helpful
ReplyDeleteYou are welcome. Thanks for the appreciation.
ReplyDelete