본문 바로가기

개발/Android

[Android] Jetpack Compose 를 사용하면 이런 장점이?

안녕하세요!

 

Android Compose2021년 2월 24일 Beta 를 시작으로  2022년 7월 28일 드디어 정식으로 배포 되었습니다.

Android 개발자로 먹고 살고 있음에도 불구하고 이제서야 Compose 를 사용해보게 되었네요. 

 

권장사항

Compose 를 사용하기 위해선 Android Studio Arctic Fox | 2020.3.1 이상 버전에서 작업할 것을 권장하고 있는데요, 

그냥 지금 2022년 11월 기준으로 최신 버전을 받으시면 되실겁니다.

 

Jetpack Compose 가 뭐죠?

 

 

Compose 는 기존 Layout XML UI 를 대신 하는 선언형 프로그래밍 UI 도구 키트 입니다.

 


 

선언형 프로그래밍 패러다임 이란?

 

Compose 이해  |  Jetpack Compose  |  Android Developers

Compose 이해 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Jetpack Compose는 Android를 위한 현대적인 선언형 UI 도구 키트입니다. Compose는 프런트엔드 뷰를 명령

developer.android.com

 

아마 위의 설명으로는 잘 이해가 가지 않으실 텐데요

제가 이해를 돕기 위해 간단한 샘플을 하나 만들어 보겠습니다.

 


 

각각 Android Layout XML UI 와 Compose 를 사용한 예제를 만들어 보겠습니다.

둘 다 간단한 물고기 이름을 보여주는 간단한 리스트뷰만 구현해 보았습니다.

 

Android Layout XML UI (기존 방법)

https://github.com/areemak/imperative-programming-sample-android

 

GitHub - areemak/imperative-programming-sample-android: 명령형 프로그래밍을 설명하기 위해 사용된 샘플 입니

명령형 프로그래밍을 설명하기 위해 사용된 샘플 입니다. Contribute to areemak/imperative-programming-sample-android development by creating an account on GitHub.

github.com

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private MainListAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 데이터 생성
        List<String> data = makeData();

        // adapter 생성
        mAdapter = new MainListAdapter(MainActivity.this, data);

        // RecyclerView 초기화
        RecyclerView rcvMain = findViewById(R.id.rcv_main);
        rcvMain.setAdapter(mAdapter);
        rcvMain.setLayoutManager(new LinearLayoutManager(MainActivity.this));
    }

    private List<String> makeData() {
        String[] _data = {"꽁치", "갈치", "고등어", "삼치", "멸치", "참치", "쥐치", "기타등등"};
        return Arrays.asList(_data);
    }

    static class MainListAdapter extends RecyclerView.Adapter<MainListAdapter.ViewHolder> {

        private Context mContext;
        private List<String> mData;

        public MainListAdapter(Context mContext, List<String> mData) {
            this.mContext = mContext;
            this.mData = mData;
        }

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(mContext).inflate(R.layout.layout_main_list_item, parent, false);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.bindView(mData.get(position));
        }

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

        static class ViewHolder extends RecyclerView.ViewHolder {
            TextView tvLabel;

            public ViewHolder(@NonNull View itemView) {
                super(itemView);
                tvLabel = itemView.findViewById(R.id.tv_label);
            }

            public void bindView(String data) {
                tvLabel.setText(data);
            }
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

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

</LinearLayout>

layout_main_list_item.xml

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

    <TextView
        android:id="@+id/tv_label"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        tools:text="데이터"/>
</LinearLayout>

 

결과

기존 Layout XML 로 만든 결과물

 

Compose UI (선언형 프로그래밍)

https://github.com/areemak/declarative-programming-sample-android/

 

GitHub - areemak/declarative-programming-sample-android: 선언형 프로그래밍을 설명하기 위해 사용된 샘플 입

선언형 프로그래밍을 설명하기 위해 사용된 샘플 입니다. Contribute to areemak/declarative-programming-sample-android development by creating an account on GitHub.

github.com

MainActivity.kt

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTestAndroidTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                ) {
                    val data: List<String> = makeData()
                    ListView(data)
                }
            }
        }
    }

    private fun makeData(): List<String> {
        val _data: Array<String> = arrayOf(
            "꽁치",
            "갈치",
            "고등어",
            "삼치",
            "멸치",
            "참치",
            "쥐치",
            "기타등등",
        )

        return _data.toList()
    }
}

 

결과

 

 

차이점이 보이시나요? 

일단 코드량이 압도적으로 차이가 나죠.. 

코딩 시간도 기존꺼는 15분 정도 걸렸는데 Compose 는 2분 걸렸습니다. 2분.

이렇게 차이가 날 수 있는 이유가 바로 선언형 프로그래밍의 장점이라고 할 수 있습니다.

 

기존에는 리스트 뷰를 보여주기 위해서 아래와 같은 절차들이 필요했습니다.

  1. xml 에 RecyclerView 를 선언해준다. 
  2. 코드에서 RecyclerView 를 binding 시킨다.
  3. Adapter 를 생성하고 list item 을 보여줄 layout 도 하나 생성한다. 
  4. list item layout 을 inflate 한다.
  5. ViewHolder 를 생성하고 데이터와 list item layout 을 binding 시킨다.
  6. 데이터를 생성하여 RecyclerView 와 adapter 를 연결시킨다.

이런걸 명령형 프로그래밍이라고 합니다. 일단 미리 다 만들어 놔야지만 화면에 보여지는게 가능한 방식이죠.

 

 

정말 View 하나 추가할 때마다의 그 답답함은 Android 개발자 분들이라면 다 아실거라 생각합니다..

 

Compose 를 보시면

  1. list item Composer 를 생성한다.
  2. list item 을 보여줄 list composer 를 생성한다.
  3. 데이터를 list composer 로 넘겨준다.

명령형 프로그래밍 보다 할일이 많이 줄어들었죠.

선언형 프로그래밍은 과정보단 결과물을 더 중요시 하기 때문입니다.

 

이게 무슨 소리냐면, 개발자는 그냥 결과물 데이터와 list item view 구현에만 집중하고 나머지 listView 와 데이터의 연결, 반복 등은 신경쓰지 않아도 된다는 거예요. 

 

이 방식은 요즘 많이 사용되는 React, Flutter, SwiftUI(iOS) 에도 적용되어 있습니다. 곧 선언형 프로그래밍이 대세라는 것이죠.

 

아직까지는 Compose 를 많이 다루어 보지 않아서 그런지 장점밖에 보이지 않네요..

추후에 Compose 를 사용하여 간단한 앱을 하나 만들어 보며 장점과 단점을 포스팅 해 보겠습니다.