[TIL] Android 앱 개발 심화 : 이미지 검색 어플 구현하기 1

지혜·2024년 1월 25일

Android_TIL

목록 보기
46/70

✏240125 목요일 TIL(Today I learned) 오늘 배운 것

📖TabLayout + Viewpager2로 UI틀 만들기

[build.gradle.kt(module)]

  • 뷰페이저2 사용을 위해 라이브러리 추가해주기
    implementation("androidx.viewpager2:viewpager2:1.0.0")

[activity_main.xml]

  • 탭레이아웃을 하단에 두고, 나머지 부분은 뷰페이저로 꽉 채웠다.

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.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=".MainActivity">
    
       <androidx.viewpager2.widget.ViewPager2
           android:id="@+id/main_view_pager"
           android:layout_width="match_parent"
           android:layout_height="0dp"
           app:layout_constraintBottom_toTopOf="@id/main_tab"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toTopOf="parent">
    
       </androidx.viewpager2.widget.ViewPager2>
    
       <com.google.android.material.tabs.TabLayout
           android:id="@+id/main_tab"
           android:layout_width="match_parent"
           android:layout_height="50dp"
           android:background="@color/white"
           app:layout_constraintBottom_toBottomOf="parent"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>

[ViewPager2Adapter.kt]

  • 뷰페이저에 연결할 프래그먼트를 framents 변수 안에서 배열로 관리한다.

    
    import androidx.fragment.app.Fragment
    import androidx.viewpager2.adapter.FragmentStateAdapter
    
    class ViewPager2Adapter(fragmentActivity: MainActivity) : FragmentStateAdapter(fragmentActivity) {
       private var fragments: ArrayList<Fragment> = ArrayList()
    
       override fun getItemCount(): Int {
           return fragments.size
       }
    
       override fun createFragment(position: Int): Fragment {
           return fragments[position]
       }
    
       fun addFragment(fragment: Fragment) {
           fragments.add(fragment)
           notifyItemInserted(fragments.size - 1)
       }
    
       fun removeFragement() {
           fragments.removeLast()
           notifyItemRemoved(fragments.size)
       }
    }

[MainActivity.kt]

  • initViewPager() 함수를 만들어서, 그 안에서 탭레이아웃과 뷰페이저를 연결해준다.

    
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import androidx.viewpager2.widget.ViewPager2
    import com.example.myimgsearch.databinding.ActivityMainBinding
    import com.google.android.material.tabs.TabLayoutMediator
    
    class MainActivity : AppCompatActivity() {
       private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           setContentView(binding.root)
    
           initViewPager()
       }
    
       private fun initViewPager() {
           val tabTextList = listOf("이미지 검색", "내 보관함")
    
           var viewPager2Adapter = ViewPager2Adapter(this)
           viewPager2Adapter.addFragment(SearchFragment())
           viewPager2Adapter.addFragment(StorageFragment())
    
           binding.mainViewPager.apply {
               adapter = viewPager2Adapter
               registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){})
           }
    
           TabLayoutMediator(binding.mainTab, binding.mainViewPager) { tab, position ->
               tab.text = tabTextList[position]
           }.attach()
    
       }
    }

📖카카오 API 키 가져오기 및 프로젝트에서 API 키 값 숨기기

[카카오 API 키 가져오기]

  • kakao developers에 들어가서 로그인(카카오계정 필요)을 한 후, 내 애플리케이션에 들어가서 애플리케이션 추가하기를 누르면 사용자 정보를 입력하게 된다. 여기서 앱아이콘은 등록하지 않아도 괜찮지만, 나머지 필수 값들을 입력하면 애플리케이션이 등록되는데, 눌러서 들어가보면 사용할 수 있는 네이티브 앱키, REST API 키, JavaScript 키, Admin 키를 가질 수 있다.
  • 사업자명을 입력하라고는 하는데, 정말 상업적으로 사용할 것이 아니면, 꼭 정확한 명칭들로 값을 채우지 않아도 된다고 한다....
  • 나는 카카오 이미지 검색 기능을 사용할 것이기 때문에, 여기서 REST API 키를 활용할 것이다.

[프로젝트에서 API 키 값 숨기기]

  • API 키 값은 고유한 사용자를 구별하기 때문에, 과금 등의 이유로 개인 키 값을 노출시키면 안된다. 따라서 노출을 방지하기 위해 .gitignore파일에 들어가는 /build 와 local.properties를 활용하여 git에 API키 값이 올라가는 불상사를 막을 것이다.
  • 나는 API키 값에 대해서만 이 방법을 사용했지만, BASE_URL에 대해서도 이 방법을 활용할 수 있다.

1. [local.properties] : local.properties에 api_key 변수 설정하기

  • Gradle Scripts 안에 존재하는 local.properties에 사용하고싶은변수명="제공된키값"을 작성한다.

  • 나는 변수명을 api_key라고 간단하게 적었다. 카카오 REST API 값만 사용할 것이기 때문에..

  • 제공되는 키 값은 꼭 "" 더블쿼터안에 작성하도록 하자.

    ## This file is automatically generated by Android Studio.
    # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
    #
    # This file should *NOT* be checked into Version Control Systems,
    # as it contains information specific to your local configuration.
    #
    # Location of the SDK. This is only used by Gradle.
    # For customization when using a Version Control System, please read the
    # header note.\
    
    ...
    
    api_key="제공해주는 키 값"

2. [build.gradle(module)] : build.gradle 에 properties 설정하기

  • android { } 바깥에 properties를 선언해주고, android { } 안에 있는 defaultConfig {} 안에는 buildConfigField(type,name,value)를 선언해준다.

  • [트러블슈팅] android { } 안에 있는 buildFeatures {}안에 buildConfig = true를 추가해준다. 해주지 않으면, Cause: defaultConfig contains custom BuildConfig fields, but the feature is disabled.오류를 만나게 된다..

  • [트러블슈팅] Properties()를 임포트 받을 때에는 수많은 Properties( )들이 있지만, 꼭 java.util.Properties을 임포트해줘야 load 함수를 사용할 수 있다.

  • [트러블슈팅] buildConfigField()함수를 작성해줄 때에는 value값에 "설정한변수명"이 프로퍼티임을 알 수 있도록 꼭 properties.getProperty("설정한변수명")를 사용해준다.

    
    import java.io.FileInputStream
    import java.util.Properties
    
    ...
    
    val properties = Properties().apply { load(FileInputStream(rootProject.file("local.properties"))) }
    
    android {
    	...
       defaultConfig {
       		...
               buildConfigField("String", "KAKAOAPI", properties.getProperty("api_key"))
    	}
    	...
    	buildFeatures {
    		...
    		buildConfig = true
    		...
    	}
    }
    ...
    

3. [BuildConfig가 필요한파일] : 설정한 값을 BuildConfig로 받아서 사용하기.

  • BuildConfig.buildConfigField의name형태로 원하는 곳에서 사용할 수 있다.
  • [트러블슈팅] BuildConfig가 사용이 안된다면, Build메뉴 > Rebuild Project를 통해 빌드를 다시 해주면 사용가능하다.
    val apikey : String =  BuildConfig.KAKAOAPI

✏오늘의 느낀점과 내일 할 일

[오늘의 느낀점]

  • 개인 과제를 시작하면서 일단 UI 틀 부터 만들고, 그 안에 프래그먼트를 채울려고 리사이클러뷰를 넣으려는데 리사이클러뷰를 사용하려면 데이터가 필요하고 그 데이터를 가져오려면 API가 필요하고.. 필요한 것을 찾아 찾아 흘러가는게 API 키 값 가져 와서 숨기는 거였다..ㅎ
  • API값. 가져오는 거. 직접 하는거.. 키 값 자체를 받아내는 것은 어렵지 않았는데, API 값을 숨기는데 정말.. 온갖 오류를 다 만났다. ㅎㅎ ㅎㅎ ㅎㅎㅎㅎ 이렇게 숨겨진 코드들은 강의에서 설명해주지 않았으니까 인터넷을 깡으로 뒤져가면서 했는데, 인터넷상에는 또 기본적으로 자바를 활용한 코드들이 많았어서 코틀린 코드로 작성하겠다고 이리 저리 만져보다가 오류나고.. 리빌드 과정에서도 한 두어번 오류 나고.. 아주 다사다난 했다. build.gradle 파일을 얼마나 많이 열어봤는지... 어쨌든 오늘 API 키 값 숨기기를 완료했으니까 만족하기로했다.
  • 이외에 탭레이아웃과 뷰페이저2는 사실 나는 처음.. 써보는건데..ㅎㅎ 저번 팀과제 때 팀원들이 사용하는 것을 봐서 아주 수월하게 사용할 수 있었다. Viewpager2에 대한 어댑터도 따로 있는 모습을 보고 괜히 겁먹었었는데, API 숨기는 일에 비하면 아무것도 아니다,,^^

[내일 할 일]

  • 수준별 수업에서는 오늘 retrofit 강의를 들었는데, 오늘 이 강의가 없었다면 API 값을 숨겨야한다는 결론에도 도달하지 못했을 것이다.. 어쨌든 오늘 수업을 하신 후 별 다른 과제 안내가 없어서 개인과제를 바로 시작했는데, 다음 주에는 뷰모델을 활용하는 방법을 알려주신다고 하셔서 최대한 내일..안에....... 이번주안에.. 다음 수준별 수업을 듣기 전까지..ㅎㅎ 뷰모델 없이 1차 과제를 완성하는 것이 목표가 되었다.
  • 오늘 어쨌든 API 문제는 해결했으니까, 내일 정말 retrofit을 활용하여 데이터를 가져오는 기능 구현을.. 만들면 될 것 같다. 좋아요.. 기능은.. 내일안에.. 가능하려나? 생각해보니까 보관함 기능이 있었다. 음.. 월요일까지 좋아요 보관함 기능만들고, 화수까지 뷰모델로 바꿔보고 목요일날 제출하면 될 것 같은데,, 생각처럼 될 수 있도록 내일 열심히 해야겠다.

✏참고한 블로그

profile
파이팅!

0개의 댓글