ListView에는 onItemClickListener라는 편리한 클릭 리스너가 기본 제공되지만, RecyclerView는 아이템 클릭 이벤트를 직접 처리해야 합니다. 이 글에서는 안드로이드 RecyclerView에서 onItemClickListner를 대체하는 가장 좋은 방법, 즉 커스텀 인터페이스(콜백)를 활용한 클릭 이벤트 처리 방법을 단계별로 살펴보겠습니다.
전체 구현 흐름
핵심 아이디어는 간단합니다. 어댑터(Adapter)와 액티비티(Activity) 사이에 커스텀 인터페이스를 정의하고, 뷰홀더(ViewHolder)의 아이템이 클릭되면 이 인터페이스를 통해 액티비티로 클릭 이벤트를 전달하는 것입니다.
1단계 — 새 프로젝트 생성
Android Studio에서 File ⇒ New Project를 선택하고, 새 프로젝트 생성에 필요한 모든 세부 정보를 입력하여 프로젝트를 만듭니다.
2단계 — activity_main.xml 작성
res/layout/activity_main.xml에 다음 코드를 추가합니다.
<?xml version = "1.0" encoding = "utf-8"?>
<android.support.design.widget.CoordinatorLayout android:layout_width = "match_parent"
android:layout_height = "match_parent"
xmlns:android = "https://schemas.android.com/apk/res/android"
xmlns:app = "https://schemas.android.com/apk/res-auto">
<android.support.design.widget.AppBarLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content">
<android.support.v7.widget.Toolbar
android:id = "@+id/appbarlayout_tool_bar"
android:background = "@color/colorPrimary"
android:layout_width = "match_parent"
android:layout_height = "?attr/actionBarSize"
app:layout_scrollFlags = "scroll|snap|enterAlways"
app:theme = "@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme = "@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id = "@+id/recycler_view"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
app:layout_behavior = "@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>위 코드에서는 툴바(Toolbar)와 함께 화면 전체를 차지하는 RecyclerView 하나를 배치했습니다.
3단계 — MainActivity.java 작성
src/MainActivity.java에 다음 코드를 추가합니다.
package com.example.myapplication;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
TextView text;
ArrayList<String> list = new ArrayList<>();
private RecyclerView recyclerView;
private customAdapter mAdapter;
private onClickInterface onclickInterface;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.appbarlayout_tool_bar);
toolbar.setTitle("This is toolbar.");
setSupportActionBar(toolbar);
// 클릭 이벤트를 수신하는 콜백 구현부
onclickInterface = new onClickInterface() {
@Override
public void setClick(String abc) {
if (abc != null) {
list.add(abc);
mAdapter.notifyDataSetChanged();
}
}
};
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new customAdapter(this, list, onclickInterface);
recyclerView.setAdapter(mAdapter);
recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
list.add("sairamm");
list.add("Krishna");
list.add("prasad");
list.add("sairamm");
list.add("Krishna");
list.add("prasad");
list.add("sairamm");
list.add("Krishna");
list.add("prasad");
list.add("sairamm");
list.add("Krishna");
list.add("prasad");
list.add("Krishna");
list.add("prasad");
list.add("sairamm");
list.add("Krishna");
list.add("prasad");
list.add("sairamm");
list.add("Krishna");
list.add("prasad");
}
}여기서 핵심은 onClickInterface의 익명 구현체입니다. 어댑터에서 아이템 클릭이 발생하면 setClick() 메서드가 호출되고, 여기서 리스트에 새 항목을 추가한 뒤 notifyDataSetChanged()로 화면을 갱신합니다.
4단계 — customAdapter.java 작성
src/customAdapter.java에 다음 코드를 추가합니다.
package com.example.myapplication;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
public class customAdapter extends RecyclerView.Adapter<customAdapter.MyViewHolder> {
Context context;
ArrayList<String> list;
onClickInterface onClickInterface;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
}
}
public customAdapter(Context context, ArrayList<String> list, onClickInterface onClickInterface) {
this.context = context;
this.list = list;
this.onClickInterface = onClickInterface;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, viewGroup, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, final int i) {
myViewHolder.title.setText(list.get(i));
// 아이템 클릭 시 인터페이스를 통해 액티비티에 이벤트 전달
myViewHolder.title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickInterface.setClick("onItemClick");
}
});
}
@Override
public int getItemCount() {
return list.size();
}
}어댑터는 생성자를 통해 onClickInterface 객체를 전달받습니다. 그리고 onBindViewHolder()에서 각 아이템 뷰에 클릭 리스너를 설정하여, 클릭 시 인터페이스의 setClick()을 호출함으로써 ListView의 onItemClickListener와 동일한 효과를 냅니다.
5단계 — list_row.xml 작성
res/layout/list_row.xml에 다음 코드를 추가합니다.
<?xml version = "1.0" encoding = "utf-8"?>
<android.support.v7.widget.CardView xmlns:android = "https://schemas.android.com/apk/res/android"
xmlns:app = "https://schemas.android.com/apk/res-auto"
xmlns:tools = "https://schemas.android.com/tools"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
app:cardElevation = "10dp"
app:cardCornerRadius = "20dp"
tools:context = ".MainActivity">
<LinearLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:gravity = "center"
android:orientation = "vertical">
<ImageView
android:id = "@+id/imageView2"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:src = "@drawable/logo" />
<TextView
android:id = "@+id/title"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:gravity = "center"
android:textSize = "30sp" />
<TextView
android:id = "@+id/textview2"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:gravity = "center"
android:text = "Sairamkrishan"
android:textSize = "30sp" />
</LinearLayout>
</android.support.v7.widget.CardView>각 리스트 행은 CardView로 감싸진 이미지와 두 개의 TextView로 구성됩니다.
6단계 — onClickInterface 정의
src/onClickInterface.java에 다음 코드를 추가합니다.
package com.example.myapplication;
public interface onClickInterface {
void setClick(String abc);
}이 인터페이스가 바로 RecyclerView에서 onItemClickListener를 대체하는 핵심 요소입니다. 필요에 따라 클릭된 아이템의 position(위치)을 함께 전달하도록 void setClick(int position) 형태로 확장할 수도 있습니다.
앱 실행 및 결과 확인
이제 애플리케이션을 실행해 보겠습니다. 실제 안드로이드 모바일 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤, 툴바의 Run 아이콘을 클릭하세요. 실행 옵션에서 자신의 모바일 기기를 선택하면, 모바일 기기에 다음과 같은 기본 화면이 표시됩니다.

이후 화면의 TextView를 클릭하면, 클릭 이벤트가 인터페이스를 통해 액티비티로 전달되어 다음과 같은 결과가 나타납니다.