안드로이드 Listener Interface?

Lee Jung-hwan·2023년 9월 17일
0

Android

목록 보기
4/4

주의! 이글은 개인 공부 목적으로 작성된 포스팅입니다.
잘못된 내용이 있을 수 있음을 주의해주세요.

오늘은 콜백 함수(CallBack)와 리스너 인터페이스(Listener Interface)에 대해 알아볼 예정이다.


📞 리스너 인터페이스?

우리가 흔히 안드로이드에서 사용자의 입력을 처리하기 위해선 아래와 같은 로직으로 처리할 것 이다.

btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    IonClick.show();
                }
            });

setOnClickListener에서 onClick을 Override해 아래와 같은 명령어를 실행하는 원리이다.

그럼 만약, 아래와 같은 상황에선 어떻게 해야 할까?

리사이클러뷰 아이템에서 버튼을 누르면 MainActivity 안에 있는 TextView의 숫자 값을 증가시키시오.

많은 방법이 있을 거다.

TextView를 넘겨 처리하거나, Binding을 통해 조절하는 방법 등 다양한 방법이 있을 것이다.

여러 방법 중 오늘은 리스너 인터페이스를 사용해 코드를 보다 효율적으로 관리할 수 있도록 하는 방법을 배워볼 까 한다.

위의 문제를 해결하기 위해서 아래와 같은 Interface를 만들어보자.

public interface IOnClick {
    void show();
}

그 다음 MainActivity에 implements 하고 정의해 보자.

@Override
    public void show() {
        binding.textView.setText(String.valueOf(i));
        i++;
    }

binding 같은 경우 나는 ViewBinding을 사용해서 그렇지만 다른 방식으로 구현해도 상관없다.

그리고 리사이클러뷰를 아래와 같이 만들어보자.
필자는 텍스트 뷰 1개와 버튼 1개가 포함된 커스텀 UI를 만들어 적용했다.

package velog.example.myapplication.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

import velog.example.myapplication.IOnClick;
import velog.example.myapplication.R;

public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MainHolder> {

    ArrayList<String> test;
    IOnClick IonClick;

    public MainAdapter(ArrayList<String> testList, IOnClick IonClick){
        this.test = testList;
        this.IonClick = IonClick;
    }

    @NonNull
    @Override
    public MainHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_view,parent, false);
        MainHolder holder = new MainHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull MainHolder holder, int position) {
        holder.bind(position);
    }

    @Override
    public int getItemCount() {
        return test.size();
    }


    class MainHolder extends RecyclerView.ViewHolder {

        TextView tv;
        Button btn;

        public MainHolder(@NonNull View itemView) {
            super(itemView);

            tv = itemView.findViewById(R.id.tv1);
            btn = itemView.findViewById(R.id.btn1);
        }

        public void bind(int pos){

            tv.setText(test.get(pos));

            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    IonClick.show();
                }
            });

        }

    }
}

자 그럼 거의 모든 준비가 끝났다.
이제 MainActivity에 돌아가 적용해 보자.

여기서 핵심은 IOnClick 인터페이스를 하나의 변수로 만들어 어댑터가
생성될 때 생성자를 통해 해당하는 Class에서 받아와 정의해 준다.

package velog.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;

import android.os.Bundle;
import android.view.LayoutInflater;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import velog.example.myapplication.adapter.MainAdapter;
import velog.example.myapplication.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity implements IOnClick{
    ActivityMainBinding binding;
    MainAdapter mainAdapter;
    int i = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(LayoutInflater.from(this));
        setContentView(binding.getRoot());

        ArrayList<String> name = new ArrayList<>(Arrays.asList("test1","test2","test3"));
        mainAdapter = new MainAdapter(name,this);

        binding.rec.setLayoutManager(new LinearLayoutManager(this));
        binding.rec.setAdapter(mainAdapter);

    }

    @Override
    public void show() {
        binding.textView.setText(String.valueOf(i));
        i++;
    }
}

지금 보면 어댑터에 적용된 show가 MainActivity에서 정의돼있는 걸 확인할 수 있다.

또한, this를 통해 MainActivity에서 정의한 IonClick을 어댑터에 전달하는 내용을 확인할 수 있다.

이는 쉽게 말해 어댑터에서 클릭된 이벤트로 MainActivity에서 정의한 show()가 실행된다는 점을 확인할 수 있다.

결과물을 살펴보고 이해를 도와보자.


🔍 결과물


❓ 그래서 콜백과 리스너 인터페이스 차이가 뭐야?

사실 나도 이 부분에 있어서 지금도 많은 혼동이 있지만 가장 큰 차이는 대상을 가리키는 View의 유무이다.

예를 들어 test1이라는 텍스트가 적힌 리사이클러뷰는 버튼을 누르면 onClick() 함수에 의해 show() 함수가 작동한다.

이는 test1에서 실행된 콜백 함수에 의해 가능한 내용이다.
즉, 콜백 함수는 1 : 1 방식의 대상 View를 가지는 사용자의 이벤트가 발생하면 처리할 내용을 기록하는 함수이다.

반면, 리스너는 1 : N 방식으로 특정 대상 View를 가지는 게 아닌 전달 받은 View에 어떠한 행동을 할 것인지 정의한 내용이다.

보통 콜백은 "on~~"으로 시작하는게 많다고 한다.
하지만 리스너는 on안에서 실행되는 이벤트의 정의이다.

위와 같은 차이를 잘 숙지하고 사용한다면 보다 좋은 방식으로 개발할 수 있을거라 생각된다.


👋 오늘은 여기까지!

긴 글 읽어주셔 감사하고 피드백은 언제나 환영입니다.
감사합니다.

profile
안녕하세요😁 안드로이드 개발자 이정환 입니다~⭐️

0개의 댓글