2017년 6월 20일 화요일

[Android] RecycleView 기본틀 작업하기

Standard
# RecycleView 란?
RecycleView에 대해서 잘 정리된 블로그 링크로 설명을 대신함.
ListView와의 차이점에 대해서 설명
RecycleView에 대해서 설명
RecycleView의 성능향상_1
RecycleView의 성능향상_2

결론은 ListView 사용에서 생기던 문제점들을 대폭 개선하고, 리스트 뷰의 성능을 대폭 향상 시킨 뷰 클래스이다.

# RecyclerView는 다음과 같은 요소들이 있다.
  1. Adapter - 아이템에 대한 View를 생성하고, ListView에서 사용하던 Adapter나 ArrayAdapter와 같은 역할을한다.
  2. LayoutManager - 리스트 아이템의 배치와 스크롤 방식, 형태를 결정짓는 가장 중요한 클래스다.
  3. ViewHolder - ListView에서 사용하던 ViewHolder 패턴을 RecyclerView에서는 강제하게 되면서 클래스가 생겼다. 아이템의 뷰들을 담고있다.
  4. ItemDecoration - 데이터를 나타내는 뷰를 제외하고 부수적인 뷰를 나타낼 때 사용한다.
  5. ItemAnimation - 아이템을 나타내는 뷰의 애니매이션 효과에 대해 정의 할 때 사용한다.

    # LayoutManager에 대해서
    •  LinearLayoutManager : 리사이클러 뷰에서 가장 많이 쓰이는 레이아웃으로 수평, 수직 스크롤을 제공하는 리스트를 만들 수 있음
    •  StaggeredGridLayouManager : 이 레이아웃을 통해 뷰마다 크기가 다른 레이아웃을 만들 수 있음
    • GridLayoutManager : 여러분의 사진첩 같은 격자형 리스트를 만들 수 있음.
    # ItemDecoration 사용법
    # RecyclerView 생성 구조

    • 리사이클뷰의 생성 구조 설명 블로그
    • 위의 링크된 블로그를 보면 리사이클 뷰의 동작 구조를 어느정도 이해할 수 있으며, 나름데로 이해한 것으로 Adapter에서 이루어지는 호출 순서를 그리면 아래와 같음.

    # Android에서 RecycleView 활용하기
    RecycleView를 생성하고 제어하기 위해서는 RecyclerView를 가지고 있는 Layout  XML 파일 그리고 RecyclerView 객체화 클래스(Activity or Fragment), Adapter를 확장한 사용자 정의 클래스, ViewHold Layout XML 그리고 ViewHold 확장한 사용자 클래스 마지막 DataSet에 담길 Model Bean 객체를 생성하여함. 

    • activity_main.xml - ConstraintLayout은 Android N 버전에서 새로나온 레이아웃으로 다음에 자세히 파헤쳐 보고 여기서는 RecyclerView 사용법에 대해서만 봄.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.team.tat.nofapplication.MainActivity">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/main_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </android.support.constraint.ConstraintLayout>


    cs

    • MainActivity.java - RecyclerView의 속성을 제어하기 위해서 Activity에서 RecyclerView 객체를 생성해줘야 함
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.support.v7.widget.DefaultItemAnimator;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import com.team.tat.nofapplication.adapter.MainRecycleViewAdapter;
    import com.team.tat.nofapplication.domain.Item;
    import java.util.ArrayList;
    import java.util.List;
    public class MainActivity extends AppCompatActivity {
        private RecyclerView recyclerView;
        private MainRecycleViewAdapter mainRecycleViewAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            recyclerView =(RecyclerView)findViewById(R.id.main_recyclerview);
            RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
            recyclerView.setLayoutManager(mLayoutManager);
            mainRecycleViewAdapter = new MainRecycleViewAdapter();
            recyclerView.setItemAnimator(new DefaultItemAnimator());
            recyclerView.setAdapter(mainRecycleViewAdapter);
        }
    }
    cs


    • MainRecycleViewAdapter.java - RecyclerView의 Children View를 생성하고 제어하기 위한 Adapter 객체를 구현함
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import com.team.tat.nofapplication.R;
    import com.team.tat.nofapplication.adapter.viewholder.MenuListViewHolder;
    import com.team.tat.nofapplication.domain.Item;
    import java.util.ArrayList;
    import java.util.List;
    public class MainRecycleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        private List<Item> itemList;
        /**
         * 아이템 리스트 설정하기(전체)
         * @param itemList  아이템 리스트
         */
        public void setItemDomainList(List<Item> itemList) {
            this.itemList = itemList;
        }
        /**
         * 아이템 리스트 특정 위치에 설정하기
         * @param index 리스트 아이템 설정
         * @param item 아이템
         */
        public void selectAddItemDomain(int index,Item item) {
            this.itemList.add(index,item);
        }
        /**
         * 아이템을 리스트에 추가하기(순서대로)
         * @param item 아이템
         */
        public void addItemDomain(Item item) {
            this.itemList.add(item);
        }
        /**
         * 모든 아이템 삭제하기
         */
        public void clearAllItemDomain() {
            this.itemList.clear();
        }
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            Log.d("MainRecycleViewAdapter","onCreateViewHolder viewType("+viewType+")");
            RecyclerView.ViewHolder viewHolder = null;
            switch (viewType) {
                case 2:
                    break;
                case 3:
                    break;
                default:
                    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.viewholder_1_type,parent,false);
                    viewHolder = new MenuListViewHolder(itemView);
                    break;
            }
            return viewHolder;
        }
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            Log.d("MainRecycleViewAdapter""onBindViewHolder position(" + position + ")");
            Item item = itemList.get(position);
            ///< 메뉴 리스트 홀더
            if(holder instanceof MenuListViewHolder) {
            }
        }
        /**
         * 뷰홀더의 레이아웃 종류를 가져오는 함수
         * - 아이템 도메인에 뷰홀더 종류를 가져올 수 있는 변수가 있어야 함
         * @param position 아이템 리스트에서 가져올 아이템의 순번
         * @return 레이아웃 종류
         */
        @Override
        public int getItemViewType(int position) {
            Log.d("MainRecycleViewAdapter""getItemViewType position(" + position + ")");
            if(itemList != null && itemList.size() > 0) {
                return itemList.get(position).getMenuType();
            }
            return 0;
        }
        /**
         * 아이템 리스트의 총 개수를 가져오는 함수
         * @return
         */
        @Override
        public int getItemCount() {
            Log.d("MainRecycleViewAdapter""getItemCount()");
            if(itemList == null) itemList = new ArrayList<>();
            return itemList.size();
        }
    }
    cs

    • viewholder_1_type.xml - RecyclerView의 자식뷰의 레이아웃을 구성하는 XML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <ImageView
                android:id="@+id/menu_list_imageview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight=".1"
                app:srcCompat="@mipmap/ic_launcher_round" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="horizontal"
                android:weightSum="1"
                android:layout_weight=".9"
                android:padding="10dp">
                <TextView
                    android:id="@+id/menu_title_textview"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight=".6"
                    android:gravity="center_vertical"
                    android:text="title" />
                <TextView
                    android:id="@+id/menu_count_textview"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight=".4"
                    android:gravity="center_vertical"
                    android:text="count" />
            </LinearLayout>
        </LinearLayout>
    </RelativeLayout>
    cs

    • MenuListViewHolder.java - RecyclerView의 자식뷰를 제어하기 위한 ViewHold 구현 클래스
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import com.team.tat.nofapplication.R;
    import com.team.tat.nofapplication.adapter.viewholder.MenuListViewHolder;
    import com.team.tat.nofapplication.domain.Item;
    import java.util.ArrayList;
    import java.util.List;
    public class MainRecycleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        private List<Item> itemList;
        /**
         * 아이템 리스트 설정하기(전체)
         * @param itemList  아이템 리스트
         */
        public void setItemDomainList(List<Item> itemList) {
            this.itemList = itemList;
        }
        /**
         * 아이템 리스트 특정 위치에 설정하기
         * @param index 리스트 아이템 설정
         * @param item 아이템
         */
        public void selectAddItemDomain(int index,Item item) {
            this.itemList.add(index,item);
        }
        /**
         * 아이템을 리스트에 추가하기(순서대로)
         * @param item 아이템
         */
        public void addItemDomain(Item item) {
            this.itemList.add(item);
        }
        /**
         * 모든 아이템 삭제하기
         */
        public void clearAllItemDomain() {
            this.itemList.clear();
        }
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            Log.d("MainRecycleViewAdapter","onCreateViewHolder viewType("+viewType+")");
            RecyclerView.ViewHolder viewHolder = null;
            switch (viewType) {
                case 2:
                    break;
                case 3:
                    break;
                default:
                    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.viewholder_1_type,parent,false);
                    viewHolder = new MenuListViewHolder(itemView);
                    break;
            }
            return viewHolder;
        }
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            Log.d("MainRecycleViewAdapter""onBindViewHolder position(" + position + ")");
            Item item = itemList.get(position);
            ///< 메뉴 리스트 홀더
            if(holder instanceof MenuListViewHolder) {
            }
        }
        /**
         * 뷰홀더의 레이아웃 종류를 가져오는 함수
         * - 아이템 도메인에 뷰홀더 종류를 가져올 수 있는 변수가 있어야 함
         * @param position 아이템 리스트에서 가져올 아이템의 순번
         * @return 레이아웃 종류
         */
        @Override
        public int getItemViewType(int position) {
            Log.d("MainRecycleViewAdapter""getItemViewType position(" + position + ")");
            if(itemList != null && itemList.size() > 0) {
                return itemList.get(position).getMenuType();
            }
            return 0;
        }
        /**
         * 아이템 리스트의 총 개수를 가져오는 함수
         * @return
         */
        @Override
        public int getItemCount() {
            Log.d("MainRecycleViewAdapter""getItemCount()");
            if(itemList == null) itemList = new ArrayList<>();
            return itemList.size();
        }
    }
    cs

    • Item.java - RecyclerView의 DataSet에 담길 Model 객체
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public class Item {
        private String menuTitle; ///< 메뉴제목
        private int menuType; ///< viewholder 종류
        private int itemCount; ///< 항목 개수(하루총 뉴스 건수)
        private String description; ///< 메뉴 설명 :: 음성합성 메뉴설명으로 사용함
        public String getMenuTitle() {
            return menuTitle;
        }
        public void setMenuTitle(String menuTitle) {
            this.menuTitle = menuTitle;
        }
        public int getMenuType() {
            return menuType;
        }
        public void setMenuType(int menuType) {
            this.menuType = menuType;
        }
        public int getItemCount() {
            return itemCount;
        }
        public void setItemCount(int itemCount) {
            this.itemCount = itemCount;
        }
        public String getDescription() {
            return description;
        }
        public void setDescription(String description) {
            this.description = description;
        }
    }
    cs

    • 위의 사용법이 기본 Android에서 사용되는 기본 코딩 구조이다. 개발자 스타일에 따라 다른 구조를 사용하여도 되고, 구글링을 하면 다양한 방법이 존재한다.
    • 다만, 나는 기본에서 프로젝트를 진행하면서 그때그때 환경에 맞게 변경하는 스타일이라 기본 구조만 작성하였음
    # 참고사이트