I am trying to understand callbacks in Java, but it's confusing me a lot. I know callbacks are passed as an object by implementing interface. But I'm not able to understand how the functions of those passed objects in arguments are invoked.
I took this example
interface ClickEventHandler {
public void handleClick();
}
//Step 2: Create a callback handler
//implementing the above interface
class ClickHandler implements ClickEventHandler {
public void handleClick() {
System.out.println("Clicked");
}
}
//Step 3: Create event generator class
class Button {
public void onClick(ClickEventHandler clickHandler) {
clickHandler.handleClick();
}
}
public class Tester {
public static void main(String[] args) {
Button button = new Button();
ClickHandler clickHandler = new ClickHandler();
//pass the clickHandler to do the default operation
button.onClick(clickHandler);
Button button1 = new Button();
//pass the interface to implement own operation
button1.onClick(new ClickEventHandler() {
#Override
public void handleClick() {
System.out.println("Button Clicked");
}
});
}
}
Output is
```none
Clicked Button
Clicked.
I mean to invoke the function of passed objects we need to register it and call the functions. How does it work in case of listeners? It would be helpful if someone guide me in understanding this.
Well, you'd normally maintain a reference to ClickEventHandler (or even a list if you want to support multiple) and call the method when the button is clicked.
Example:
class Button {
private ClickEventHandler clickHandler;
public void onClick(ClickEventHandler clickHandler) {
this.clickHandler = clickHandler;
}
public void click() {
if( clickHandler != null ) {
clickHandler.handleClick();
}
}
Now when you invoke onClick() the listener is only registered and it will only be executed when the button is clicked (i.e. you call the click() method).
Its easy you just need to create interface
interface HandleClick {
void onItemClick(Boolean success);
}
There's some function to do some work and you need something to return
public static void someFunctions(String params, HandleClick handleClick) {
//some work to do here.
handleClick.onItemClick(true);
}
You can call it anywhere
class Main extends AppCompatActivity {
#Override
public void onCreate(#Nullable Bundle savedInstanceState, #Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
Callbacks.someFunctions("param", new HandleClick() {
#Override
public void onItemClick(Boolean success) {
}
});
}
}
I wrote a simple code to understand how we can do the same callback in 2 different ways.
interface InterestingEvent
{
public void interestingEvent ();
}
public class Test
{
private InterestingEvent ie;
public void EventNotifier (InterestingEvent event)
{
ie = event;
ie.interestingEvent();
}
public static void main(String[] args) {
Test test= new Test();
test.EventNotifier(new InterestingEvent() {
#Override
public void interestingEvent() {
System.out.println("I am callback code");
}
});
}
}
public class Test implements InterestingEvent{
#Override
public void interestingEvent() {
System.out.println("Hello i am callback code");
}
public void EventNotifier ()
{
this.interestingEvent();
}
public static void main(String[] args) {
Test test =new Test();
test.EventNotifier();
}
}
Related
I've been trying to find a way to create a listener for a boolean on an android code reader. Essentially what I want to happen is, when it stops reading, perform action. So far I've based it off of this example, and have this:
Class:
public class scanStatusListener {
ScanManager scanManager;
private boolean scanStatus = scanManager.isReading(); //this returns if the reader is scanning or not
private ChangeListener listener;
public void setListener(ChangeListener listener) {
this.listener = listener;
}
public interface ChangeListener {
void onChange();
}
}
Activity:
public class ScanHook extends Service implements ScanManager.DataListener, scanStatusListener.ChangeListener{
private ScanManager _scanManager;
#Override
public void onCreate() {
super.onCreate();
_scanManager = ScanManager.createScanManager(getApplicationContext());
scanStatusListener ss = new scanStatusListener();
ss.setListener(new scanStatusListener.ChangeListener() {
public void onChange() {
//perform action
}
});
}
The issue I am getting is:
private boolean scanStatus = scanManager.isReading();
is getting an error saying that I cannot invoke on a null object reference.
I also tried using the LiveData suggestion:
MutableLiveData<Boolean> listen_bool=new MutableLiveData<>();
listen_bool.observe((LifecycleOwner) this, new Observer<Boolean>() {
#Override
public void onChanged(Boolean aBoolean) {
//perform action
}
});
listen_bool.setValue(_scanManager.isReading());
however I am getting an error saying I cannot cast to androidx.lifecycle.LifecycleOwner
Any suggestions?
I'm working with two classes, and model class and a dialog class in android. The model class keeps a list of listeners, which the dialog adds to.
public class SmartChannelModel {
private List<OnResultsChanged> mOnResultsChanged
public interface OnResultsChanged {
void onResultsChanged(int changed);
}
public SmartChannelModel() {
mOnResultsChanged = new List<OnResultsChanged>();
}
public void addResultListener(OnResultsChanged listener) {
mOnResultsChanged.add(listener);
}
}
And my dialog class:
public class InfoDialog extends AppCompatDialog {
private SmartChannelModel model;
public InfoDialog(Context context, SmartChannelModel model) {
super(context);
this.model = model;
}
public void update() {
//do some stuff
}
#Override
protected void onStart() {
super.onStart();
model.addOnResultsChanged(new OnResultsChanged() {
#Override
void onResultsChanged(int changed) {
update();
}
});
}
}
When I create and dismiss this dialog, will garbage collection ever be performed on it since the dialog added a listener to the model class? Do I need to specifically remove any listeners that I've added?
Thank you for the help!
As far as i know Yes if there is no other reference to it anywhere in the class.
I try a Toast Message interface. If app not connection internet, I want show a Toast Message and I'm wanting java interfaces.
This is MotherActivity.java. This file implement ToastMessagges.ToastMessaggeCallback
public class MotherActivity extends ActionBarActivity implements ToastMessagges.ToastMessaggeCallback {
ToastMessagges toastMessagges;
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mother);
toastMessagges = new ToastMessagges();
AppStarter();
}
private void AppStarter(){
boolean checkinternet = InternetControl.checkInternetConnection( getApplicationContext() );
if( checkinternet ) {
toastMessagges.show_toast_messagge();
}
else {
}
}
#Override
public void LongToastMessagge() {
Toast.makeText(getApplicationContext(), "Hello World", Toast.LENGTH_LONG).show();
}
}
This is my ToastMessagges.java file.
public class ToastMessagges {
ToastMessaggeCallback toastMessaggeCallback;
public void show_toast_messagge(){
toastMessaggeCallback.LongToastMessagge();
}
public static interface ToastMessaggeCallback {
public void LongToastMessagge();
}
}
When the start this app. I get NullPointerException error.
Caused by: java.lang.NullPointerException
at com.medyasef.bulenttirasnewapp.bulenttiras.functions.ToastMessagges.show_toast_messagge(ToastMessagges.java:22)
at com.medyasef.bulenttirasnewapp.bulenttiras.MotherActivity.AppStarter(MotherActivity.java:36)
at com.medyasef.bulenttirasnewapp.bulenttiras.MotherActivity.onCreate(MotherActivity.java:29)
ToastMessagges.java:22
toastMessaggeCallback.LongToastMessagge();
Sorry bad english.
Please help.
Thank you.
You haven't initialized you ToastMessaggeCallback toastMessaggeCallback.
To do this, write
ToastMessaggeCallback toastMessaggeCallback = new ToastMessaggeCallback(){
public void LongToastMessagge(){
// add some toasting code here
}
};
This will make an object implementing your interface (called "anonymous class"). Of course, your ToastMessaggeCallback should do something in the method LongToastMessagge, so add the desired code there.
I will recommend you to create a Util class instead of Interface. I'm here giving you an example of Util class.
public class Util {
public static void showToast(Context context, String text) {
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
}
}
Then call the showToast() method from your activity as follows...
Util.showToast(YourActivity.this, "text");
Update:
Declare your Interface as a individual, not inside a class as below...
public interface ToastMessaggeCallback {
public void showLongToastMessagge(String text);
}
Then implement the Interface as follows...
public class MotherActivity extends ActionBarActivity implements ToastMessaggeCallback {
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mother);
AppStarter();
}
private void AppStarter(){
boolean checkinternet = InternetControl.checkInternetConnection( getApplicationContext() );
if( checkinternet ) {
showLongToastMessagge("Hello World");
}
else {
}
}
#Override
public void showLongToastMessagge(String text) {
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
}
}
Your ToastMessagges class needs to provide a method to register the callback. Then, your Activity needs to call this method to register itself as the callback, right after you construct the ToastMessages object.
I need to connect to facebook so I use a Tread when using the network. but I have a problem:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
FacebookConnectTask task = new FacebookConnectTask("facebookId", "token", "email", facebookGender,0, 0);
task.setOnPreExecuteListener(this);
task.setOnDoneListener(this);
task.execute();
}
});
t.start();
}
I cant do
task.setOnPreExecuteListener(this);
task.setOnDoneListener(this);
eclipse gives me this error: "The method setOnDoneListener(Task.OnDoneListener) in the type Task is not applicable for the arguments (new Runnable(){})"
How can i fix this?
Thanks!
You've changed context's by being in a Thread your in an Annoyomous class, this is now your annonomous class and not the outer class.
Try this (pun intended):
task.setOnPreExecuteListener(YourOuterClass.this);
task.setOnDoneListener(YourOuterClass.this);
i.e.
public class YourClass implements OnDoneListener {
public doFacebook(){
new Thread(new Runnable(){
#Override
public void run(){
task.setOnDoneListener(YourClass.this);
}
}.start();
}
#Override
public void onDone(){
}
}
or alternatively pull your Threaded class out:
public class DoSomething implements Runnable {
private final OnDoneListener listener;
public DoSomething(OnDoneListener listener){
this.listener = listener;
}
#Override
public void run(){
FacebookConnectTask task = ... ;
task.setOnDoneListener(listener);
}
}
public class YourActivity extends Activity implements OnDoneListener {
public void onCreate(Bundle b){
new Thread(new DoSomething(this)).start();
}
#Override
public void onDone(){
// Tada
}
}
A further step if you wanted to be cooler is create your own interface and keep all the Facebook stuff in the runnable class:
public class DoSomething implements Runnable, OnDoneListener {
public interface OnFacebookFinished {
void onFacebookFinished();
}
private final OnFacebookFinished listener;
public DoSomething(OnFacebookFinished listener){
this.listener = listener;
}
#Override
public void run(){
FacebookConnectTask task = ... ;
task.setOnDoneListener(this);
}
#Override
public void onDone(){
if(listener != null){
listener.onFacebookFinished();
}
}
}
public class YourActivity extends Activity implements OnFacebookFinished {
#Override
public void onCreate(Bundle b){
new Thread(new DoSomething(this)).start();
}
#Override
public void onFacebookFinished(){
// Tada
}
}
public interface DownloadListener {
public void onDownloaded();
}
public class DownloadManager {
private static DownloadManager instance;
private DownloadListener mDownloadListener;
public static synchronized DownloadManager getInstance(){
if(instance == null)
instance = new DownloadManager();
return instance;
}
private DownloadManager() {
myHandler.sendEmptyMessageDelayed(29, 3 * 1000);
}
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListener = downloadListener;
}
Handler myHandler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
if (msg.what == 29) {
mDownloadListener.onDownloaded();
return true;
}
return false;
}
});
}
public class I implements DownloadListener {
public I() {
DownloadManager.getInstance().registerDownloadListener(this);
}
#Override
public void onDownloaded() {
Log.e("TAG", "I onDownloaded");
}
}
public class You implements DownloadListener {
public You() {
DownloadManager.getInstance().registerDownloadListener(this);
}
#Override
public void onDownloaded() {
Log.e("TAG", "You onDownloaded");
}
}
public class PATTERNSActivity extends Activity implements DownloadListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new I();
new You();
DownloadManager.getInstance().registerDownloadListener(this);
}
#Override
public void onDownloaded() {
Log.e("TAG","PATTERNSActivity onDownloaded");
}
}
I am expecting to get:
I onDownloaded
You onDownloaded
PATTERNSActivity onDownloaded
But I am getting only:
PATTERNSActivity onDownloaded
What could it be the problem?
You keep registered downloaders in a single instance property:
// Last call's downloadListener wins.
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListener = downloadListener;
}
The last one registered is the activity's:
new I(); // First set singleton's property to an instance of I...
new You(); // ...then to an instance of You...
// ...then to the current instance.
DownloadManager.getInstance().registerDownloadListener(this);
Edit based on your comment.
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListeners.add(downloadListener);
}
...
public boolean handleMessage(Message msg) {
if (msg.what != 29) {
return false;
}
for (DownloadListener listener : mDownloadListeners) {
listener.onDownloaded();
}
return true;
}
In your code, this gets executed by calling mDownloadListener.onDownloaded(); in the DownloadManager class.
#Override
public void onDownloaded() {
Log.e("TAG","PATTERNSActivity onDownloaded");
}
In don't see why the onDownloaded methods of the I and YOU class should be executed, they're never called. Only the OnDownloaded method of your Listener is called.
For starters, I think you are not using a list. You just override the value so you will always get the last one:
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListener = downloadListener;
}