Android

안드로이드(android) 리사이클러뷰(RecyclerView)에 아이템 추가 및 삭제방법

리사이클러뷰(RecyclerView)

리사이클러뷰(RecyclerView)는 리스트뷰(ListView)와 사용목적과 동작 방식이 매우 유사하다. 리스트뷰의 단점을 보완하기에 리스트뷰를 쓰는 일은 이제 없을 것이다. 많은 데이터를 불러와 표시하여도 메모리 부족에 따른 프로그램 강제 종료의 상황은 발생하지 않는다. 리스트뷰를 사용시 스크롤을 내리다 보면 화면이 버벅거리는 현상이 발생한다.

리사이클러뷰는 이런 현상이 사라졌다. 그만큼 리스트뷰(ListView)를 사용할 이유가 없어졌다고 본다. 리사이클러뷰를 시작해보자.

[스탭1] 리사이클러뷰를 사용하기위해 build.gradle(Module:app)파일을 열고 아래 라이브러리를 추가해준다.

dependencies {
……………
implementation ‘androidx.recyclerview:recyclerview:1.1.0’
}

RecyclerView를 만들기 위해서는 RecyclerView 레이아웃과 RecyclerView의 ItemView, Adapter, Value Obejct 클래스 등 총 4 가지가 필요하다.

[스탭2] 메인액티비티(activity_main.xml)에 리사이클러뷰를 추가한다. 리사이클러뷰에 리스트 데이터를 뿌려줄 것이다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />    
</LinearLayout>

[스탭2-1] 리사이클러뷰에서 사용될 아이템뷰 레이아웃(recyclerview_item.xml)을 추가한다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/text_view"
        android:text="1"
        android:textSize="30sp"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/text_content"
        android:layout_marginStart="20dp"
        android:text="test"
        android:textSize="30sp"/>
</LinearLayout>

[스탭2-2] 삭제시 사용할 다이얼로그 레이아웃 추가.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_blue_shape_radius"
    android:gravity="center">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:id="@+id/topLayout"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="12dp"
        android:layout_marginRight="10dp"
        android:gravity="center_vertical">

        <ImageView
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:id="@+id/imageView3"
            android:background="@drawable/push_icon"/>

        <TextView
            android:id="@+id/content_text_view"
            android:layout_width="254dp"
            android:layout_height="wrap_content"
            android:text="삭제할까요?n삭제 후 복구는 할 수 없습니다."
            android:layout_marginLeft="5dp"
            android:textSize="20sp"
            android:textColor="@color/colorxml_color_41"
            android:layout_gravity="center_vertical"
            android:layout_marginRight="10dp" />
    </LinearLayout>


    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="@color/colorxml_color_41"
        android:layout_marginBottom="10dp"/>

    <LinearLayout
        android:id="@+id/bottomLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="15dp"
        android:orientation="horizontal">
        <LinearLayout
            android:id="@+id/linearLayout3"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="@drawable/update_bg_left_shape_radius"
            android:gravity="center_vertical|center"
            android:layout_marginRight="2.5dp"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/btn_no_text"
                android:textColor="@color/colorxml_color_41"
                android:textSize="17sp"
                android:textStyle="bold" />
        </LinearLayout>
        <LinearLayout
            android:id="@+id/linearLayout4"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="@drawable/bg_btn_shape_radius"
            android:gravity="center_vertical|center"
            android:layout_marginLeft="2.5dp"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/textView4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/btn_yes_text"
                android:textColor="@color/colorxml_color_41"
                android:textSize="17sp"
                android:textStyle="bold" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

[스탭3] Value Object를 생성하자. 리스트 레이아웃에 뿌려줄 데이터를 담아놓은 클래스를 만드는 것이다.

public class TestVo {
    private String id;
    private String content;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

	//제너레이트 기능을 사용하여 생성자를 생성하면 편리하다.
    public TestVo(String id, String content) {
        this.id = id;
        this.content = content;
    }
}

[스탭4] 리사이클러뷰 어댑터 클래스를 만들자.

import androidx.recyclerview.widget.RecyclerView;
public class TestRecyclerViewAdapter extends RecyclerView.Adapter<TestRecyclerViewAdapter.ItemViewHolder>{

    private ArrayList<TestVo> mList;
    private int position;
    public TestRecyclerViewAdapter(ArrayList<TestVo> list){
        this.mList = list;
    }

    // 뷰홀더 상속 및 구현
    public class ItemViewHolder extends RecyclerView.ViewHolder{
        protected TextView id;
        protected TextView content;

          public ItemViewHolder(@NonNull final View itemView) {
            super(itemView);
            this.id = itemView.findViewById(R.id.text_view);
            this.content = itemView.findViewById(R.id.text_content);
        }

        public void onBind(TestVo vo){
            id.setText(vo.getId());
            content.setText(vo.getContent());
        }
    }

    @NonNull
    @Override
    public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.recyclerview_item, viewGroup, false);

        ItemViewHolder viewHolder = new ItemViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ItemViewHolder viewholder, final int position) {
        viewholder.onBind(mList.get(position));

        viewholder.content.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
           		setPosition(position); //클릭한 아이템 position set
                showDeleteDialog(vo, v); //삭제 다이얼로그 호출
            }
        });

        viewholder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(v.getContext(), position +"번째 리스트클릭!", Toast.LENGTH_SHORT).show();
            }
        });
    }



    @Override
    public int getItemCount() {
        return (null != mList ? mList.size() : 0);
    }

    public ArrayList<TestVo> getListData() {
        return mList;
    }

    public void setListData(ArrayList<TestVo> listData) {
        this.mList = listData;
    }

}

[스탭5] 아이템 추가 및 삭제 메소드 추가하기

import androidx.recyclerview.widget.RecyclerView;
public class TestRecyclerViewAdapter extends RecyclerView.Adapter<TestRecyclerViewAdapter.ItemViewHolder>{

    ....생략........
    private int position;
    
    ....생략........
    
    //아이템 추가 메소드
    public void addItem(TestVo data) {
        mList.add(data);
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }
 
	//아이템 삭제 메소드
    public void removeItem(int position) {
        itemList.remove(position);
        notifyItemRemoved(position);
        //갱신처리 반드시 해야함
        notifyDataSetChanged();
    }

    private void showDeleteDialog(final MyNumbers vo, View v){
        final Dialog deelteDialog = new Dialog(v.getContext());
        deelteDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        deelteDialog.setContentView(R.layout.dialog_yes_no);
        if(deelteDialog.getWindow()!=null)
            deelteDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0));        //Android: how to create a transparent dialog-themed activity

        setFontTextView((TextView) deelteDialog.findViewById(R.id.textView4));
        setFontTextView((TextView) deelteDialog.findViewById(R.id.textView3));
        setFontTextView((TextView) deelteDialog.findViewById(R.id.content_text_view));

        LinearLayout linearLayout3 = (LinearLayout) deelteDialog.findViewById(R.id.linearLayout3);
        linearLayout3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v.getId() == R.id.linearLayout3) {
                    if ( deelteDialog != null && deelteDialog.isShowing()) {
                        deelteDialog.dismiss();
                    }
                }
            }
        });

        LinearLayout linearLayout4 = (LinearLayout) deelteDialog.findViewById(R.id.linearLayout4);
        linearLayout4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v.getId() == R.id.linearLayout4) {
                    if ( deelteDialog != null && deelteDialog.isShowing()) {
                        deelteDialog.dismiss();

                        removeItem(getPosition());

                     }

                }
            }
        });

        if (context != null && !((Activity) context).isFinishing()) {
            deelteDialog.show();
        }
    }
}
     

[스탭6] 메인액티비티클래스(RecyclerViewActivity)에 리사이클러뷰에 대한 선언 및 초기화를 진행하자.

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class RecyclerViewActivity extends AppCompatActivity {

    private ArrayList<TestVo> mArrayList;
    
	// 어댑터 선언
    private TestRecyclerViewAdapter mAdapter;
    int dataCount = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);
 
        RecyclerView mRecyclerView = findViewById(R.id.recycler_view);

        // 리사이클러뷰에 LinearLayoutManager 지정(vertical)
        LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLinearLayoutManager);
        //mRecyclerView.setHasFixedSize(true);
        //setHasFixedSize(true) 메서드는 리사이클러뷰 안 아이템들의 크기를 가변적으로 적용할지, 일정한 고정 크기를 적용할지를 지정한다. 
        //만약 false값으로 적용하면 매번 아이템들의 크기를 계산해야 하므로 성능 저하가 발생할 수 있다.
        

        // 수평으로 리사이클러뷰 아이템을 배치하고자 할때..
        //mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)) ;
        
        // 리사이클러뷰에 뿌려줄 데이터를 담을 ArrayList를 초기화
        mArrayList = new ArrayList<TestVo>();
 
        // 리사이클러뷰에 표시할 데이터 리스트 생성(임으로 100개)
        for (int i=0; i<100; i++) {
            mArrayList.add(new TestVo(String.valueOf(i), "샘플" + String.valueOf(i))); 
           //String.format("샘플 %d", i)
        }
        
        // 어댑터에 리스트에 뿌려줄 ArrayList를 적용.
        mAdapter = new TestRecyclerViewAdapter( mArrayList);
        mRecyclerView.setAdapter(mAdapter);
	
        // notifyDataSetChanged를 호출하여 adapter의 값이 변경되었다는 것을 알려준다.
        mAdapter.notifyDataSetChanged();

리사이클러뷰 아이템 추가 메소드 호출 방법 , 삭제 방법

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class RecyclerViewActivity extends AppCompatActivity {

    private ArrayList<TestVo> mArrayList;
    
	// 어댑터 선언
    private TestRecyclerViewAdapter mAdapter;
    int dataCount = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);
 
        ..............생략..................
		//아이템 추가 테스트
        mAdapter.addItem(new TestVo(String.valueOf(101), "별도샘플" + String.valueOf(101)));
        
        // notifyDataSetChanged를 호출하여 adapter의 값이 변경되었다는 것을 알려준다.
        mAdapter.notifyDataSetChanged();
               
        
        //삭제 테스트
        mAdapter.removeItem(mAdapter.getPosition());
    }
}

삭제버튼을 하나 추가해서 클릭이벤트를 주고 삭제를 해도 되며, 리사이클러뷰내에 리스트에 버튼을 생성하거나 메뉴를 생성하여 처리하여도 된다

[연관 글 더보기]

[프로그래밍/Android] – 안드로이드 리사이클러뷰(RecyclerView)를 사용하자. ListView는 버린다!!

Leave a Reply

error: Content is protected !!