Is this the proper usage of a callback? - java

I have an addProductButton, click it and it brings up a DialogBox containing bookNameTextBox, bookCategoryTextBox and addBookButton. Click addBookButton, it inserts the bookNameTextBox and bookCategoryTextBox contents into a database. If successful, it should hide the DialogBox and updateList()
The following code works to accomplish that but I'm not sure if it's proper or if there is a better way to achieve the same results.
Main class
addProductButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
//display addBookDialogBox
AddBookDialog abd = new AddBookDialog();
abd.displayDialog(new Callback() {
#Override
public void onSuccess() {
updateList();
}
public void onFailure() {
}
});
}
});
public void updateList() {
}
AddBookDialog class
public class AddBookDialog extends DialogBox {
private Callback callback;
private static AddBookDialogUiBinder uiBinder = GWT
.create(AddBookDialogUiBinder.class);
interface AddBookDialogUiBinder extends UiBinder<Widget, AddBookDialog> {
}
public AddBookDialog() {
setWidget(uiBinder.createAndBindUi(this));
}
public void displayDialog(Callback callback2) {
callback = callback2;
this.center();
}
#UiHandler("addBookButton")
void onAddBookButtonClick(ClickEvent event) {
//save book to database
Database db = Database.openDatabase("Store", "1.0", "My Store", 5 * 1024 * 1024);
db.transaction(new TransactionCallback() {
public void onTransactionStart(SQLTransaction tx) {
tx.executeSql("INSERT INTO products (bookName, bookCategory) VALUES (?, ?)", new Object[] { bookNameTextBox.getText().toString(), bookCategoryTextBox.getText().toString() });
}
public void onTransactionFailure(SQLError error) {
}
public void onTransactionSuccess() {
callback.onSuccess();
}
});
this.hide();
}
}
Callback interface
public interface Callback {
void onSuccess();
void onFailure();
}

I don't see the use of it here, why don't you just put updateList(); inside the onTransactionStart() method ?
CallBacks are used for Asynchronism, and the TransactionCallback here already does that, so I don't see why you would use another callback inside.
And by the way, if you did need a callback, why don't you use the AsyncCallback provided by gwt?
EDIT :
Then the appropriate way is to make an interface with your updateList() method. Make your main class implement it, and change the parameter type of your displayDialog() method to your interface type instead of CallBack type.

Related

how the interface works?

I am trying to understand how interfaces work. I have read basic interface tutorials online and watched a few videos so i do have a good idea of what a interface is and its advantages.
Interface
public interface UpyunFormApi {
#Description("上传文件")
#POST("/{bucket}")
#Multipart
public Request upload(#Path("bucket") String bucket, #Part("policy") PolicyPart policy,
#Part("signature") SignaturePart signature, #Part("file") File file, OnRequestListener requestListener,
OnResponseListener<UpyunFormEntity> responseListener, OnErrorListener errorListener);
Code
private UpyunFormApi formApi;
private void uploadAndPushTopic() {
String bucket = UrlManager.getInstance().getUpyunImageBucket();
String secret = UrlManager.getInstance().getUpyunImageSecret();
for (File file : filearr) {
PolicyPart policy = new PolicyPart(bucket);
SignaturePart signature = new SignaturePart(policy, secret);
formApi.upload(bucket, policy, signature, file, uploadRequestListener, uploadResponseListener,
uploadErrorListener);
}
}
private OnRequestListener uploadRequestListener = new OnRequestListener() {
#Override
public void onRequest(Request arg0) {
}
};
private OnErrorListener uploadErrorListener = new OnErrorListener() {
#Override
public void onError(LegolasException arg0) {
}
};
private OnResponseListener<UpyunFormEntity> uploadResponseListener = new OnResponseListener<UpyunFormEntity>() {
#Override
public void onResponse(UpyunFormEntity arg0) {
}
}
};
Why the Responselister works after "formApi.upload()" finished?And I can't find function definition.Help!
I don't understand the code
#Description("上传文件")
#POST("/{bucket}")
#Multipart
Make an interface like :
public interface ChangeItemInterface {
public void doChange(String anyValue);
}
In Adapter,
Intialize interface object like :
ChangeItemInterface changeItemInterface;
In Adapter Constructor,
this.changeItemInterface = context;
In Adapter, From any View Click :
AnyView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
this.changeItemInterface.doChange("AnyValue");
// It will go to the Your Activity Overided method which is explained below this
}
});
In Your Activity implement this interface like :
public class YourActivity extends Activity implements ChangeItemInterface{
/// You'll get override method of your interface, here your call back will come when from adapter click happen
#Override
public void doChange(String anyValue) {
/// Here you can update any value in your activity !
}
}
Hope this demo help you to understand interface use !

Callback Listener in Unity - How to call script file method from UnityPlayerActivity in Android

I have an android library project and imported the library project in the Unity project. Now, I want to implement a callback in Unity project, which will execute according to the response given by the android library project. I mean to say, Call Script File method from UnityPlayerActivity (Android Project).
Currently I am using below line of code but nothing happens:
UnityPlayer.UnitySendMessage("Main Camera","showMessage",errorMessage);
Main Camera is my Game Object. showMessage is message name in Script File.
Message is message which will be displayed in Unity through Android Activity.
Please check my below code Unity Script File and Android Activity.
Unity Script File:
using UnityEngine;
using System.Collections;
public class scriptfile : MonoBehaviour {
// Use this for initialization
void Start () {
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("shareText","236","236");
}
void showMessage(string message){
print ("hello");
Debug.Log ("hello");
}
}
Android File UnityPlayerActivity:
/**
* Created by CH-E01073 on 28-09-2015.
*/
public class MainAct extends UnityPlayerActivity implements RegistrationListener,BOffersListener {
Context context;
SharedPreferences prefs ;
String AppIds="";
String PublisherIDs="";
public void shareText(String AppId,String PublisherID) {
context=MainAct.this;
prefs = PreferenceManager
.getDefaultSharedPreferences(context);
Log.e("AppID", AppId);
Log.e("PublisherID",PublisherID);
AppIds=AppId;
PublisherIDs=PublisherID;
runOnUiThread(new Runnable() {
#Override
public void run() {
UnityPlayer.UnitySendMessage("Main Camera","showMessage","Start UI Thread");
if (prefs.getString(FreeBConstants.ID, null) == null
|| prefs.getString(FreeBConstants.ID, null).equals("")
|| !Build.VERSION.RELEASE.equals(prefs.getString(
FreeBConstants.VERSION, null))
|| !FreeBCommonUtility.getDeviceId(context).equals(
(prefs.getString(FreeBConstants.DEVICE_ID, null)))) {
BSDKLogger.enableLogging(true);
SDKRegistration.initialize(MainAct.this, getApplicationContext(), AppIds,PublisherIDs);
}else{
Offers Offers = new Offers(MainAct.this);
Offers.setOnFreeBOffersListener(MainAct.this);
Offers.setTitle(
"Pick Any Offer to unlock your premium features",
"#FFFFFF", "#FF6D00");
}
}
});
}
#Override
public void onOffersLoaded(String code,String freeBOffers) {
CommonUtility.showToast(getApplicationContext(), code);
UnityPlayer.UnitySendMessage("Main Camera","showMessage",freeBOffers);
}
#Override
public void onShowOffers() {
UnityPlayer.UnitySendMessage("Main Camera","showMessage","Show Offers");
}
#Override
public void noOfferInstalled(String s, String s2) {
}
#Override
public void onLeaveApplication(String s, String s2) {
}
#Override
public void onDialogDismiss(String s) {
}
#Override
public void onOffersFailed(String code, String errorMessage) {
FreeBCommonUtility.showToast(getApplicationContext(), errorMessage);
UnityPlayer.UnitySendMessage("Main Camera","showMessage",errorMessage);
}
#Override
public void onOffersInstallSuccess(String code, String errorMessage) {
FreeBCommonUtility.showToast(getApplicationContext(), errorMessage);
}
#Override
public void onOffersInstallFailure(String code, String errorMessage) {
FreeBCommonUtility.showToast(getApplicationContext(), errorMessage);
}
#Override
public void onRegistrationFailed(String code, String errorMessage) {
FreeBCommonUtility.showToast(getApplicationContext(), errorMessage);
UnityPlayer.UnitySendMessage("Main Camera","showMessage",errorMessage);
}
#Override
public void onRegistrationSuccess(String code, String errorMessage) {
// FreeBCommonUtility.showToast(getApplicationContext(), errorMessage);
Log.e("SUCCESS", errorMessage);
// TODO Auto-generated method stub
UnityPlayer.UnitySendMessage("Main Camera","showMessage",errorMessage);
Offers Offers = new Offers(MainAct.this);
Offers.setOnFreeBOffersListener(MainAct.this);
Offers.setTitle(
"Pick Any Offer to unlock your premium features",
"#FFFFFF", "#FF6D00");
}
}
Can anyone help me to get rid of this issue?
Another option will be to implement an interface callback using AndroidJavaProxy. Instead of using UnitySendMessage, you can simply have an Interface callback in your java code and then implement this interface in C# using AndroidJavaProxy and pass it to the Java method in order to receive messages back.
Create your Java interface:
package com.example.android;
public interface PluginCallback {
public void onSuccess(String videoPath);
public void onError(String errorMessage);
}
Call the passed listener/callback to return messages
public void myPluginMethod(PluginCallback callback) {
// Do something
callback.onSuccess("onSuccess");
// Do something horrible
callback.onError("onError");
}
Implement the interface in C#
class AndroidPluginCallback : AndroidJavaProxy
{
public AndroidPluginCallback() : base("com.example.android.PluginCallback") { }
public void onSuccess(string videoPath) {
Debug.Log("ENTER callback onSuccess: " + videoPath);
}
public void onError(string errorMessage)
{
Debug.Log("ENTER callback onError: " + errorMessage);
}
}
Pass the C# interface to the Java method
AndroidJavaObject pluginClass = new AndroidJavaObject("com.example.android.MyPlugin");
pluginClass.Call("myPluginMethod", new AndroidPluginCallback());
I believe you are only allowed to call UnitySendMessage() from the main thread - at least in one scenario above you are calling it from the Android UI worker thread.
As a quick sanity test, try calling it before you right at the top of your shareText() function.

Can I generify the following code?

I have some methods in a class like this:
#Override
public void sendRemoteRecord(String token, int channelId, int eventId, final ServiceCallback<RemoteRecordResponse> callback) {
epgServicesApiManager.sendRemoteRecord(token, channelId, eventId)
.observeOn(scheduler)
.subscribe(new Action1<RemoteRecordResponse>() {
#Override
public void call(RemoteRecordResponse model) {
if (callback != null)
callback.onSuccess(model);
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
if (callback != null)
callback.onError();
}
});
}
#Override
public void activateRemoteRecord(String token, String cardNumber, final ServiceCallback<RemoteRecordActivateResponse> callback) {
epgServicesApiManager.activateRemoteRecord(token, cardNumber)
.observeOn(scheduler)
.subscribe(new Action1<RemoteRecordActivateResponse>() {
#Override
public void call(RemoteRecordActivateResponse remoteRecordActivateResponse) {
if (callback != null)
callback.onSuccess(remoteRecordActivateResponse);
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
if (callback != null)
callback.onError();
}
});
}
Is it possible to remove the duplication around the code after the observeOn() line?
The annoying part is making sure I do the null check on the callback before using it.
At present, I know of seven distinct methods I need in this class and possibly more.
Unfortunately, in Java 1.7 there is no way to fix this without increasing the amount of code. You can reduce the amount of code needed locally, by introducing some helper classes.
One solution is to move your anonymous inner classes to top-level classes. From there you can introduce a dummy callback and some null-checking work an an abstract class.
It may end up looking something like this (horizontal rules are used to highlight that these classes are in separate files).
This is a dummy callback class, it does exactly nothing, but is safe to call against. This will replace the null values.
public class NullServiceCallBack<T> implements ServiceCallBack<T> {
#Override
public void onSuccess(T target) {}
#Override
public void onError() {}
}
This is an abstract class that handles the validation, converting null values to instances of NullServiceCallback:
public abstract class CallBackAction<T> implements Action1<T> {
private final ServiceCallBack<T> Callback;
public CallBackAction(ServiceCallBack<T> callback) {
this.Callback = (null != callback) ? callback : new NullServiceCallBack<>();
}
protected ServiceCallBack<T> getCallback() {
return Callback;
}
}
This is the concrete class you'll use for success.
public class SuccessCallbackAction<T> extends CallBackAction<T> {
public SuccessCallbackAction(ServiceCallBack<T> callback) {
super(callback);
}
#Override
public void call(T target) {
getCallback().onSuccess(target);
}
}
This is the concrete class for errors. This doesn't do anything with the arguments to call, so we can make this implement for Object once and be done with it.
public class ErrorCallbackAction extends CallBackAction<Object> {
public ErrorCallbackAction(ServiceCallBack<Object> callback) {
super(callback);
}
#Override
public void call(Throwable target) {
getCallback().onError();
}
}
So in the end, your example above should look something like this:
#Override
public void sendRemoteRecord(String token, int channelId, int eventId, final ServiceCallback<RemoteRecordResponse> callback) {
epgServicesApiManager.sendRemoteRecord(token, channelId, eventId)
.observeOn(scheduler)
.subscribe(new SuccessCallbackAction<RemoteRecordResponse>(callback),
new ErrorCallbackAction(callback));
}
#Override
public void activateRemoteRecord(String token, String cardNumber, final ServiceCallback<RemoteRecordActivateResponse> callback) {
epgServicesApiManager.activateRemoteRecord(token, cardNumber)
.observeOn(scheduler)
.subscribe(new SuccessCallbackAction<RemoteRecordActivateResponse>(callback),
new ErrorCallbackAction(callback));
}
Locally, we've reduced the amount of code, and made the intent a little more clear. Globally, we've increased the complexity with the addition of 4 new classes. Whether this is worth it depends on the context your code lives in, and is your call.
Introduce a dummy callback that does nothing, then do safeCallback().onSuccess() or safeCallback().onError()
Also, you can do this:
class SuccessCallback<T> extends Action1<T>() {
#Override
public void call(T value) {
safeCallback().onSuccess(value);
}
}
class ErrorCallback extends Action1<Throwable>() {
#Override
public void call(T value) {
safeCallback().onError();
}
}
then...
subscribe(new SuccessCallback<RemoteRecordActivateResponse>(), new ErrorCallback());
Does this work?

How to make an annotation event system?

I'm trying to make an annotation-based event system where like you would register a class implementing an interface and then you can use the events that have an #interface above the methods that are called. Like so:
Wherever.java
EventManager.callEvent(new HelloEvent);
EventManager.register(new ClassThatImplementsListeenr);
#EventHandler
public void onHello(HelloEvent event) {
event.sayHello();
}
Ok I understand a lot of this like registering (adds them to arraylist) and making a listener interface plus Event interface. New Events will implement Event, and an #Interface called EventHandler that will only work with methods. THE MAIN part is what I don't get. How to invoke and check for the annotation.
EDIT I JUST MADE THIS, WOULD IT WORK?
Public class EventManager {
private static List<Listener> registered = new ArrayList<Listener>();
public static void register(Listener listener) {
if (!registered.contains(listener)) {
registered.add(listener);
}
}
public static void unregister(Listener listener) {
if (registered.contains(listener)) {
registered.remove(listener);
}
}
public static List<Listener> getRegistered() {
return registered;
}
public static void callEvent(final Event event) {
new Thread() {
public void run() {
call(event);
}
}.start();
}
private static void call(final Event event) {
for (Listener listener : registered) {
Method[] methods = listener.getClass().getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(EventHandler.class)) {
try {
method.invoke(listener.getClass().newInstance(), event);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
}
}
You can check for annotations that have been added to a method by
Retrieving all the methods that are available on a class:
public void registerListeners(T handler){
Method[] allMethods = handler.getClass().getMethods();
}
Check all the methods that have your desired annotation (although I would imagine only one method in any given class should be designated with an event listener-type annotation)
List<Method> listenerMethods = new ArrayList<Method>();
for (Method aMethod: allMethods){
if(aMethod.isAnnotationPresent(EventHandler.class)){
listenerMethods.add(aMethod);
}
}
Given the specific methods that have the annotation, you could call Method#invoke on the shortlist of methods to execute the listener.

How to select one of GWT CellTree nodes after first data fetch?

I'm trying to select first root node of the CellTree after asynchronous data fetching from server. Here is my code:
public class MyTreeModel implements TreeViewModel{
private MyServiceAsync myService = GWT.create(MyService.class);
public <T> NodeInfo<?> getNodeInfo(T value) {
Cell<MyTO> cell = new AbstractCell<MyTO>() {
#Override
public void render(Context context, MyTO value, SafeHtmlBuilder sb) {
//rendering node...
}
};
return new DefaultNodeInfo<MyTO>(value instanceof MyTO ?
createBranchDataProvider((MyTO)value) : //fetching child nodes
cerateRootDataProvider(), cell); //fetching root nodes
}
#Override
public boolean isLeaf(Object value) {
if (value instanceof MyTO) {
MyTO to = (MyTO)value;
return to.isLeafNode();
}
return false;
}
private AbstractDataProvider<MyTO> cerateRootDataProvider() {
AsyncDataProvider<MyTO> dataProvider = new AsyncDataProvider<MyTO>() {
#Override
protected void onRangeChanged(HasData<MyTO> display) {
AsyncCallback<List<MyTO>> callback = new AsyncCallback<List<MyTO>>() {
#Override
public void onSuccess(List<MyTO> result) {
updateRowCount(result.size(), true);
updateRowData(0, result);
}
#Override
public void onFailure(Throwable caught) {
Window.alert(caught.toString());
}
};
myService.getRootNodes(callback);
}
};
return dataProvider;
}
private AbstractDataProvider<MyTO> createBranchDataProvider(final MyTO value) {
AsyncDataProvider<MyTO> dataProvider = new AsyncDataProvider<MyTO>() {
#Override
protected void onRangeChanged(HasData<MyTO> display) {
AsyncCallback<List<MyTO>> callback = new AsyncCallback<List<MyTO>>() {
#Override
public void onSuccess(List<MyTO> result) {
updateRowCount(result.size(), true);
updateRowData(0, result);
}
#Override
public void onFailure(Throwable caught) {
Window.alert(caught.toString());
}
};
myService.getChildNodes(value.getId(), callback);
}
};
return dataProvider;
}
For data which stored on client side solution looks pretty simple: we could just call something like
tree.getRootTreeNode().setChildOpen(0, true, true);
but if we want to fetch data asynchronously we will catch IndexOutOfBoundsException in case we try the same immediately after creation tree, because data is not obtained yet. How can I know when onSuccess() event will be fired in cerateRootDataProvider()? Or I could use another solution? Please suggest something.
I see two options for calling
tree.getRootTreeNode().setChildOpen(0, true, true);
in a right moment:
Direct dependency on presenter: add a constructor for your MyTreeModel object. Send corresponding presenter as a parameter. Add and call something like presenter.onDataLoadingComplete() at the end of onSuccess method.
Custom event: create your custom event. Fire it at the end of onSuccess method. Subscribe to it in some place where you can call access `tree``object. Call necessary code.

Categories