SalicBlu3
SalicBlu3

Reputation: 1914

Dynamically append functionality to Button's onclicklistener Android

Aim: I'm looking for a way to append functionality to a button's onClickListener.

Illustration

    Button trigger = new Button(getActivity());
    trigger.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            method1();
        }
    });

    Button runMethod2Button = new Button(getActivity());
    runMethod2Button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            method1();
            method2();
        }
    });

    Button runMethod3Button = new Button(getActivity());
    runMethod3Button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            method1();
            method3();
            method4();
        }
    });

I know we can do this with inheritance by calling

@Override
public void method(){
    super.method();
    // Do appended stuff
}

Or we can do it inline

new Object(){
    @Override
    public void method(){
        super();
        // Do appended stuff
    }
}

Things I've Tried

Extending the button to contain a list of Runnable Objects. Then set the on click listener to trigger all of the runnable objects.

Is there a different/more efficient way of doing this?

Upvotes: 5

Views: 970

Answers (3)

Johannes Becker
Johannes Becker

Reputation: 490

Since we don't no much about the background why you want to do so, it is hard to what is the best. If you want to have the original listener unchanged / untouched, you could use a decorator / wrapper pattern.

Wikipedia Decorator Pattern

In the concrete case this means, it is quite comparable to your Runnable approach, but you do not depend on another Interface. Everthing is handled via the View.OnClickListener, which has the following advantages:

  1. It is a generic approach with which you can even "extend" listeners to which you have no source access or which you do not want to modify.
  2. You can create the extension behaviour at runtime and you can extend already instantiated listeners (in contrast to the use of inheritance)
  3. The extensions do not have to know that they are extensions, they are just normal OnClickListeners. In your Runnable approach the extensions are "special" and for example they do not get the View paramter of the onClick method passed.

    public class OriginalOnClickListener implements View.OnClickListener{
    
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this,"Original Click Listener",Toast.LENGTH_LONG).show();
        }
    }
    
    public class ExtensionOnClickListener implements View.OnClickListener{
    
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this,"Extension Click Listener",Toast.LENGTH_LONG).show();
        }
    }
    
    public class DecoratorOnClickListener implements View.OnClickListener {
    
        private final List<View.OnClickListener> listeners = new ArrayList<>();
    
        public void add(View.OnClickListener  l) {
            listeners.add(l);
        }
    
        @Override
        public void onClick(View v) {
            for(View.OnClickListener l : listeners){
                l.onClick(v);
            }
        }
    }
    

And the usage is like this:

    DecoratorOnClickListener dl = new DecoratorOnClickListener();

    dl.add(new OriginalOnClickListener());
    dl.add(new ExtensionOnClickListener());

    editText.setOnClickListener(dl);

Upvotes: 4

CtrlF
CtrlF

Reputation: 674

I think the Runnable idea is okay, based on what you've said here. Seeing as I don't really know why you need dynamic click handlers, I think a possible solution would look something like this:

private class DynamicOnClickListener implements View.OnClickListener {

    private final List<Runnable> mRunnables = new ArrayList<>();

    public void add(Runnable r) {
        mRunnables.add(r);
    }

    @Override
    public void onClick(View v) {
        for (Runnable r : mRunnables) {
            r.run();
        }
    }
}

And you'd use it like this:

    DynamicOnClickListener listener = new DynamicOnClickListener();

    listener.add(new Runnable() {
        @Override
        public void run() {
            doSomething();
        }
    });

    listener.add(new Runnable() {
        @Override
        public void run() {
            doSomethingElse();
        }
    });

    mButton.setOnClickListener(listener);

Upvotes: 1

Tyler Sebastian
Tyler Sebastian

Reputation: 9448

what about something like

 Button trigger = new Button(getActivity());
 trigger.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
         method1();
         if (someVar) method2();
         if (someVar2) method3();
     }
 })

Upvotes: 0

Related Questions