안드로이드 앱 개발 숙련

남궁현·2023년 8월 25일
0

Android

목록 보기
10/15
  • 오늘은 캠프에서 지급 된 안드로이드 앱 개발 숙련 과정 강의를 마무리 개인과제를 시작했다.

ViewBinding

  • 뷰 바인딩 기능을 사용하면 뷰와 상호작용하는 코드를 쉽게 작성할 수 있다.
  • 모듈에서 사용 설정된 뷰 바인딩은 모듈에 있는 각 XML 레이아웃 파일의 결합 클래스를 생성한다.
  • 바인딩 클래스의 인스턴스에는 상응하는 레이아웃에 ID가 있는 모든 뷰의 직접 참조가 포함된다.
  • 대부분의 경우 뷰 바인딩이 findViewById를 대체한다.

NullSafe

  • 뷰 바인딩은 뷰의 Direct References 즉 직접 참조를 생성하므로 유효하지 않은 뷰ID로 인해 null포인터 예외(NPE)가 발생 할 위험이 없다.
  • 레이아웃에 아직 생성되지 않은 뷰의 참조를 얻어(null상태)해당 뷰의 속성을 사용하려 할 때 발생하는 NPE를 방지 한다.
  • 레이아웃의 일부 구성에만 뷰가 있는 경우 결합 클래스에서 참조를 포함하는 필드가@Nullable로 표시된다.

TypeSafe

  • 각 바인딩 클래스에 있는 필드의 유형이 XML파일에서 참조하는 뷰와 일치한다.
  • 클래스 변환 예외가 발생할 위험이 없다.
  • 쉽게말해 타입을 가지고 있기 때문에 imageView.text 같이 타입이 다른 경우 발생하는 오류를 방지 할 수 있다.

설정법

  • gradle 설정
    version에 따라서 설정법이 2개로 나뉜다.

    android{
    ...
    
    // AndroidStudio 3.6 ~ 4.0
    viewBinding{
    	enabled = true
    }
    
    // AndroidStudio 4.0 ~
    buildFeatures{
    	viewBinding = true
     	}
    }
  • Activity 설정법

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
    
    
   
   

AdapterView

  • 어댑터 뷰는 여러개의 항목을 다양한 형식으로 나열하고 선택 할 수 있는 기능을 제공하는 뷰를 말한다.

Adapter

  • 데이터를 관리하며 데이터 원본과 어댑터뷰(ListView, GridView) 사이의 중계 역할을 한다.

  • Adapter가 어댑터를 사용하기 위해서는 먼저 데이터 원본이 Adapter에 설정되어야 하고, AdapterView에는 Adapter가 설정되어야 한다.

  • Adapter의 getCount()란 메소드를 통해 현재 어뎁터가 관리하는 데이터 항목의 총 개수를 반환한다.

  • AdapterView는 Adapter의 getView()란 메소드를 통해서 화면에 실제로 표시할 항목뷰를 얻고, 이를 화면에 표시한다.

  • 사용자가 어댑터뷰의 특정 위치의 항목을 선택하였을 때, 어댑터뷰는 선택된 항목, 항목ID, 항목뷰를 어댑터의 getItem(), getItemId(), getView()
    메소드를 통해 얻어와서 이를 항목 선택 이벤트 처리기에 넘겨준다.

종류

  • BaseAdapter
    • 어댑터 클래스의 공통 구현
    • 사용자 정의 어댑터 구현 시 사용
  • ArrayAdapter
    • 객체 배열이나 리소스에 정의된 배열로부터 데이터를 공급받음
  • CursorAdapter
    • 데이터베이스로부터 데이터를 공급받음
  • SimpleAdapter
    • 데이터를 Map(키,값)의 리스트로 관리
    • 데이터를 XML파일에 정의된 뷰에 대응시키는 어댑터

리스트뷰와 그리드뷰는 간단하게 설명만

  • ListView는 리스트 형태의 데이터를 수직으로 보여주기 위한 위젯이다.
    따라서 list 형태의 원본 데이터가 있어야 하며 이를 adapter를 통해 각각의 아이템에 지정해준다. 이 때 어댑터는 데이터를 관리할 뿐만 아니라 뷰도 생성해준다. 이와 같은 형태로 쓰이는 위젯이 많기 때문에 리스트뷰를 통해 기본적인 사용법을 익히는 것이 좋다.

  • gridView는 핸드폰 갤러리를 생각해보면 된다. 수직이 아닌 격자 형식으로 나타난다. 이미지를 보여주기 적합한 뷰다.

    CustomView

  • 어댑터 뷰의 항목 하나는 단순한 문자열이나 이미지뿐만 아니라,다수의 문자열이나 이미지를 포함하는 임의의 뷰를 말한다. 리사이클러뷰나 리스트뷰 등의 들어가는 아이템 뷰들이다.

  <ImageView
      android:id="@+id/goods_image"
      android:layout_width="100dp"
      android:layout_height="100dp"
      android:background="@drawable/corners_round"
      android:src="@drawable/ic_launcher_background"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintVertical_bias="1.0" />

  <TextView
      android:maxLines="2"
      android:ellipsize="end"
      android:id="@+id/g_name"
      android:layout_width="250dp"
      android:layout_height="wrap_content"
      android:text="@string/goods_name"
      android:textStyle="bold"
      android:layout_marginLeft="20dp"
      android:textSize="17sp"
      android:textColor="@color/black"
      app:layout_constraintLeft_toRightOf="@id/goods_image"
      app:layout_constraintTop_toTopOf="parent"/>

  <TextView
      android:maxLines="2"
      android:ellipsize="end"
      android:id="@+id/exp"
      android:layout_width="250dp"
      android:layout_height="wrap_content"
      android:text="@string/experience"
      android:layout_marginTop="10dp"
      android:layout_marginLeft="20dp"
      android:textSize="15sp"
      android:textColor="@color/light_gray"
      app:layout_constraintLeft_toRightOf="@id/goods_image"
      app:layout_constraintTop_toBottomOf="@id/g_name"/>

  <TextView
      android:id="@+id/g_price"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/price"
      android:textSize="14sp"
      android:textColor="@color/black"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toStartOf="@+id/exp"
     app:layout_constraintTop_toBottomOf="@+id/exp" />

RecyclerView

  • RecyclerView란 한 화면에 표시할 수 없는 많은 데이터를 스크롤 가능한 리스트로 표시해주는 위젯이다.

  • RecyclerView 사용하면 대량의 데이터 셋을 효율적으로 표시할 수 있다.

  • 리스트뷰는 아이템을 스크롤을 할 때마다 아이템이 생성하고 삭제 되는 걸 반복하지만 리사이클러뷰는 위에 있던 아이템을 재활용을 하는 것이기에 성능 면에서 훨씬 뛰어나다.

  • 리사이클러뷰도 따로 의존성 추가 해줘야합니다 ~!~!

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/main_page_category_name"
    android:textColor="@color/black"
    android:textSize="25sp"
    android:textStyle="bold|italic"
    app:layout_constraintBottom_toTopOf="@+id/recyclerView"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.048"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.333" />

<ImageButton
    android:id="@+id/imageButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:src="@drawable/ic_baseline_keyboard_arrow_down_24"
    app:layout_constraintBottom_toBottomOf="@+id/textView"
    app:layout_constraintStart_toEndOf="@+id/textView"
    app:layout_constraintTop_toTopOf="@+id/textView"
    app:layout_constraintVertical_bias="0.0" />

<ImageButton

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:src="@drawable/ic_baseline_notifications_none_24"
    app:layout_constraintBottom_toTopOf="@+id/recyclerView"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.925"
    app:layout_constraintStart_toEndOf="@+id/imageButton"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.333" />

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="405dp"
    android:layout_height="645dp"
    android:layout_marginBottom="4dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent" />

adapter class

class GoodsAdapter(val mGoods: MutableList<GoodsData>) :
RecyclerView.Adapter<GoodsAdapter.Holder>() {

// onCreateViewHolder 메소드는 새로운 ViewHolder 객체를 생성합니다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
    val binding =
        RecycleItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    return Holder(binding)
}

// onBindViewHolder 메소드는 ViewHolder와 데이터를 연결합니다.
override fun onBindViewHolder(holder: Holder, position: Int) {
    holder.goodsImage.setImageResource(mGoods[position].gImage)
    holder.name.text = mGoods[position].gName
    holder.exp.text = mGoods[position].gExp
    holder.price.text = mGoods[position].gPrice
}

// getItemCount 메소드는 어댑터가 관리하는 데이터 아이템의 수를 반환합니다.
override fun getItemCount(): Int {
    return mGoods.size
}

// getItemId 메소드는 아이템의 고유 식별자를 반환합니다.
override fun getItemId(position: Int): Long {
    return position.toLong()
}

// ViewHolder 클래스는 각 아이템의 뷰 요소들을 보유합니다.
inner class Holder(val binding: RecycleItemBinding) : RecyclerView.ViewHolder(binding.root) {
    val goodsImage = binding.goodsImage
    val name = binding.gName
    val exp = binding.exp
    val price = binding.gPrice
}

}

MainActivity.kt

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)

    val dataList = mutableListOf<GoodsData>()
    dataList.add(GoodsData(R.drawable.sample1, "산진 한달된 선풍기 팝니다", "이사가서 필요가 없어졌어요 급하게 내놓습니다", "1,000"))
    dataList.add(GoodsData(R.drawable.sample2, "김치냉장고", "이사로인해 내놔요", "870,000"))
    dataList.add(GoodsData(R.drawable.sample3, "샤넬 카드지갑", "고퀄지갑이구요\\n사용감이 있어서 싸게 내어둡니다", "970,000"))
    dataList.add(GoodsData(R.drawable.sample4, "금고", "금고\\n떼서 가져가야함\\n대우월드마크센텀\\n미국이주관계로 싸게 팝니다", "390,000"))
    dataList.add(GoodsData(R.drawable.sample5, "갤럭시Z플립3 팝니다", "갤럭시 Z플립3 그린 팝니다\\n항시 케이스 씌워서 썻고 필름 한장챙겨드립니다\\n화면에 살짝 스크래치난거 말고 크게 이상은없습니다!", "210,000"))
    dataList.add(GoodsData(R.drawable.sample6, "프라다 복조리백", "까임 오염없고 상태 깨끗합니다\\n정품여부모름", "1,200,000"))
    dataList.add(GoodsData(R.drawable.sample7, "울산 동해오션뷰 60평 복층 펜트하우스 1일 숙박권 펜션 힐링 숙소 별장", "울산 동해바다뷰 60평 복층 펜트하우스 1일 숙박권\\n(에어컨이 없기에 낮은 가격으로 변경했으며 8월 초 가장 더운날 다녀가신 분 경우 시원했다고 잘 지내다 가셨습니다)\\n1. 인원: 6명 기준입니다. 1인 10,000원 추가요금\\n2. 장소: 북구 블루마시티, 32-33층\\n3. 취사도구, 침구류, 세면도구, 드라이기 2개, 선풍기 4대 구비\\n4. 예약방법: 예약금 50,000원 하시면 저희는 명함을 드리며 입실 오전 잔금 입금하시면 저희는 동.호수를 알려드리며 고객님은 예약자분 신분증 앞면 주민번호 뒷자리 가리시거나 지우시고 문자로 보내주시면 저희는 카드키를 우편함에 놓아 둡니다.\\n5. 33층 옥상 야외 테라스 있음, 가스버너 있음\\n6. 고기 굽기 가능\\n7. 입실 오후 3시, 오전 11시 퇴실, 정리, 정돈 , 밸브 잠금 부탁드립니다.\\n8. 층간소음 주의 부탁드립니다.\\n9. 방3개, 화장실3개, 비데 3개\\n10. 저희 집안이 쓰는 별장입니다.", "210,000"))
    dataList.add(GoodsData(R.drawable.sample8, "샤넬 탑핸들 가방", "샤넬 트랜디 CC 탑핸들 스몰 램스킨 블랙 금장 플랩백 !\\n + \"\\n\" + \"색상 : 블랙\\n\" + \"사이즈 : 25.5cm * 17.5cm * 8cm\\n\" + \"구성 : 본품더스트\\n\" + \"\\n\" + \"급하게 돈이 필요해서 팝니다 ㅠ ㅠ", "3,800,000"))
    dataList.add(GoodsData(R.drawable.sample9, "4행정 엔진분무기 판매합니다.", "3년전에 사서 한번 사용하고 그대로 둔 상태입니다. 요즘 사용은 안해봤습니다. 그래서 저렴하게 내 놓습니다. 중고라 반품은 어렵습니다.\\n", "50,000"))
    dataList.add(GoodsData(R.drawable.sample10, "셀린느 버킷 가방", "22년 신세계 대전 구매입니당\\n + \"셀린느 버킷백\\n\" + \"구매해서 몇번사용했어요\\n\" + \"까짐 스크래치 없습니다.\\n\" + \"타지역에서 보내는거라 택배로 진행합니당!\"", "1,350,000"))

    binding.recyclerView.adapter = GoodsAdapter(dataList)
    val adapter = GoodsAdapter(dataList)
    binding.recyclerView.adapter = adapter
    binding.recyclerView.layoutManager = LinearLayoutManager(this)
}
}

dataClass

data class GoodsData(val gImage:Int, val gName:String, val gExp: String,val gPrice:String)

내일은 프레그먼트와 개인과제의 대해서 다뤄볼 예정 물론 지금 올린 코드도 개인과제 진행 중인 코드지만요

profile
신입 안드로이드 개발자

0개의 댓글