I wrote a compound component and was adding a custom listener to react.
Inside the class for the compound component which uses an xml file.
public class VerticalCounterBlock extends LinearLayout {
public interface VerticalCounterBlockListener {
public void onCountChanged(int newCount);
}
private VerticalCounterBlockListener mVerticalCounterBlockListener = null;
public void setVerticalCounterBlockListener(VerticalCounterBlockListener listener){
mVerticalCounterBlockListener = listener;
}
// ... Other functions
}
I got my interface, I got the listener and I got the setter and I engage the listener like this in the button I have in the compound component. I can see that toast that is showing there when I test
addBtn = (Button)findViewById(R.id.btn_addcount);
addBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
count++;
counttv.setText(String.format("%1$d", count));
Toast.makeText(getContext(), "VCB", Toast.LENGTH_SHORT).show();
if(mVerticalCounterBlockListener != null) {
mVerticalCounterBlockListener.onCountChanged(count);
}
}
});
In my main activity
m20_vcb = (VerticalCounterBlock) findViewById(R.id.vcb_m20);
m20_vcb.setVerticalCounterBlockListener(new VerticalCounterBlock.VerticalCounterBlockListener() {
#Override
public void onCountChanged(int newCount) {
increasePreachCountTotal();
Toast.makeText(CounterActivity.this, String.format("%1$d", newCount), Toast.LENGTH_SHORT).show();
}
});
I do not see that toast nor does it engage the function call. What am I missing?
I can suggest you several improvement scope here mainly restructuring the current format.
Lets not keep the interface as a inner class. So here's your VerticalCounterBlockListener.java
public interface VerticalCounterBlockListener {
public void onCountChanged(int newCount);
}
Now implement this interface in your MainActivity
public class MainActivity implements VerticalCounterBlockListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
m20_vcb = (VerticalCounterBlock) findViewById(R.id.vcb_m20);
m20_vcb.setVerticalCounterBlockListener(this);
}
// ... Other methods
// Override the onCountChanged function.
#Override
public void onCountChanged(int newCount) {
increasePreachCountTotal();
Toast.makeText(CounterActivity.this, String.format("%1$d", newCount), Toast.LENGTH_SHORT).show();
}
}
You might consider removing the Toast from the addBtn click listener which might create exception.
addBtn = (Button)findViewById(R.id.btn_addcount);
addBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
count++;
counttv.setText(String.format("%1$d", count));
if(mVerticalCounterBlockListener != null) {
mVerticalCounterBlockListener.onCountChanged(count);
}
}
});
This was good there was something wrong with my system. i uninstaklled app and restarted computer and it worked as expected.
Related
I have created an application that I used about 44 short audio records.
For each I have created a button. But, sometimes the sound of a specific button doesn't work.
How can I fix it
I will post a part of the code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first__window);
play_1= MediaPlayer.create(this,R.raw.a1);
play_2= MediaPlayer.create(this,R.raw.a2);
play_3= MediaPlayer.create(this,R.raw.a3);
play_4= MediaPlayer.create(this,R.raw.a4);
}
public void btn_1(View view)
{
play_1.start();
}
public void btn_2(View view)
{
play_2.start();
}
public void btn_3(View view)
{
play_3.start();
}
public void btn_4(View view)
{
play_4.start();
}
I don't know if I have to add some functions to avoid that problem.
You can use onClick Listener to such a manner.
You can do the followings :
btn_2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
play_2= MediaPlayer.create(this,R.raw.a1);
play_2.start();
while(play_2.isPlaying()) ;
play_2.release();
}
});
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?
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:
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.
You can create the extension behaviour at runtime and you can extend already instantiated listeners (in contrast to the use of inheritance)
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);
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);
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();
}
})
how can I make listener for multiple buttons in Android with for loop? Like in java :
private class Akcija implements ActionListener {
public void actionPerformed(ActionEvent e){
for(int r=0;r<brDugm;r++){
if (e.getSource() == b[r]) {
....
}
}
}
for(int r=0;r<brDugm;r++)
{
// Assuming b[r] is your button as object
// Assuming your action has is a function in your class Currentclass
b[r].addOnClickListener(new OnClickListener() {
public void onClick()
{
Currentclass.this.actionOnClick();
}
});
}
Your activity should implement the interface View.OnClickListener, and override the OnClick(View view) method.
And then you do something like this:
for ( int i=0;i<numButtons; i++ )
{ buttons[i].setOnClickListener(this);
}
And in your OnClick(View view) method you implement your code.
I want to create by code an array of objects that are subclasses of Button.
public class MyButton extends Button {
private Context ctx;
private int status;
public MyButton(Context context) {
super(context);
ctx = context;
status = 0;
}
private click() {
status = 1;
// OTHER CODE THAT NEEDS TO STAY HERE
}
}
In the main activity I do this:
public class myActivity extends Activity {
private MyButton[] myButtons = new MyButton[100];
#Override
public onCreate(Bundle si) {
super.onCreate(si);
createButtons();
}
private void createButtons() {
for (int w=0; w<100; w++) {
myButtons[w] = new MyButton(myActivity.this);
myButtons[w].setOnClickListener(new View.onClickListener() {
public void onClick(View v) {
// ... (A)
}
});
}
}
}
Now I want the click() method inside MyButton to be run each time the button is clicked.
Seems obvious but it is not at my eyes.
If I make the click() method public and run it directly from (A), I get an error because myButtons[w].click() is not static and cannot be run from there.
In the meantime, I an not able to understand where to put the code in the MyButton class to intercept a click and run click() from there. Should I override onClick? Or should I override onClickListener? Or what else should I do?
How can I run click() whenever one of myButtons[] object is clicked?
Thanks for the help.
You can cast View v you got in listener to MyButton and call click on it:
private void createButtons() {
View.OnClickListener listener = new View.onClickListener() {
public void onClick(View v) {
((MyButton) v).click();
}
};
for (int w=0; w<100; w++) {
myButtons[w] = new MyButton(myActivity.this);
myButtons[w].setOnClickListener(listener);
}
}
you can add:
View.onClickListener onclick = new View.onClickListener() {
public void onClick(View v) {
((MyButton)v).click();
//since v should be instance of MyButton
}
};
to your Activity
then use:
myButtons[w].setOnClickListener(onclick);
//one instance of onclick is enough, there is no need to create it for every button
in createButtons()
but ... why, oh why array of buttons we have ListView in android ...
I have made a custom component like Mybutton.java
and I have set an onclick listener in Mybutton.java.
Now, in my new activity, I have to call a Mybutton
and add content in onclick listener.
However, if I use OnClickListener mClickListener = new OnClickListener(){......
it will replace the old content.
I hope it can do the old and new listener together.
I have searched for some information, found out i can implement this method.
After many attempts, I'm still getting errors.
Can anyone give me a simple example
that i can learn to modify it?
I don't think there's an API in the Android API that allows multiple onClick listeners. You'd need some custom class that handles a single onClick() and pass in handlers for it to call. Something like this:
private class CompositeOnClickListener implements View.OnClickListener{
List<View.OnClickListener> listeners;
public CompositeOnClickListener(){
listeners = new ArrayList<View.OnClickListener>();
}
public void addOnClickListener(View.OnClickListener listener){
listeners.add(listener);
}
#Override
public void onClick(View v){
for(View.OnClickListener listener : listeners){
listener.onClick(v);
}
}
}
When your setting your buttons, do:
CompositeOnClickListener groupListener = new CompositeOnClickListener();
myButton.setOnClickListener(groupListener);
Then, whenever you want to add another listener, just call
groupListener.addOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
**** Custom implementation ****
}
});
You could create your custom Button class something like this :
public class MyButton extends Button {
private CustomOnClickListener mCustomOnClickListener;
public interface CustomOnClickListener {
void onClick(View v);
}
public MyButton(Context context) {
super(context);
// Set your own onClickListener
View.OnClickListener ocl = new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you want to do
// Invoke the other added onclick listener
if(mCustomOnClickListener != null) {
mCustomOnClickListener.onClick(v);
}
}
};
setOnClickListener(ocl);
}
// use this function to set the other onclick listener
public void setCustomOnClickListener(CustomOnClickListener cl) {
mCustomOnClickListener = cl;
}
}
and, use it like this :
// create your button
MyButton button = new MyButton(context);
// add your custom onClickListener
button.setCustomOnClickListener(new MyButton.CustomOnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you intend to do after the actual onClickListener
// from MyButton class has been invoked.
}
});
If you want to execute some internal logic in your custom view's onClick and want to execute the externally set up OnClickListener's logic, I think a simple way is overriding setOnClickListener as below.
In Kotlin:
override fun setOnClickListener(externalOnClickListener: View.OnClickListener?) {
val internalOnClickListener = View.OnClickListener { view ->
//Your awesome internal logic
externalOnClickListener?.onClick(view)
}
super.setOnClickListener(internalOnClickListener)
}
Same in Java:
#Override
public void setOnClickListener(#Nullable final View.OnClickListener externalOnClickListener) {
View.OnClickListener internalOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
//Your awesome internal logic
if (externalOnClickListener != null) {
externalOnClickListener.onClick(view);
}
}
};
super.setOnClickListener(internalOnClickListener);
}