How to shorten findViewById and setOnClickListener for similar Buttons?

Viewed 186

Is there a way to shorten the code if you have a lot of buttons with similar use? There have to be ways, however I'm not yet experienced enough to come up with a different solution. Take the following code for example:

    btn_0 = findViewById(R.id.btn_0);
    btn_1 = findViewById(R.id.btn_1);
    btn_2 = findViewById(R.id.btn_2);
    btn_3 = findViewById(R.id.btn_3);
    btn_4 = findViewById(R.id.btn_4);
    btn_5 = findViewById(R.id.btn_5);

    btn_0.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            view_input.setText("0");
            function();
        }
    });

    btn_1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            view_input.setText("1");
            function();
        }
    });

    btn_2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            view_input.setText("2");
            function();
        }
    });

    btn_3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            view_input.setText("3");
            function();
        }
    });

    btn_4.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            view_input.setText("4");
            function();
        }
    });

    btn_5.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            view_input.setText("5");
            function();
        }
    });

What options are there to write this more efficient and with less repetitive code? I have seen an option like this, however I have no clue how this is actually working:

    private Button[] btns = new Button[4];

for (int i = 0; i < 4; i++) {
    this.btns[i] = super.findViewById(new int[]{R.id.btn1, R.id.btn2, R.id.btn3, R.id.btn4}[i]);
}

If you come up with a solution I would really appreciate a short explanation why this way is working. Thanks for your effort :)

4 Answers

If you just want to avoid the principle of DRY (Don't Repeat Yourself) you can create the listener in a function and pass the text parameter like:

View.OnClickListener createOnClickListener(String text) {
  new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            view_input.setText(text);
            function();
        }
    }
}

Example Usage

btn_4.setOnClickListener(createOnClickListener("4"))

Consider ViewBinding if you're specifically tired of having to do findViewById:

from the example docs, it allows you to do something like this

private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}

binding.getName().setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

We are using https://jakewharton.github.io/butterknife/ so we can write this

@OnClick({R.id.button0,R.id.button1,R.id.button2,R.id.button3,R.id.button4})
  public void setText(View view){
      switch(view.getId()){
         case R.id.button0:
             break;
         .....
         .....
      }
  }
Related