2024.01.25(목) TIL

quinones·2024년 1월 25일

kakao API

그중에서 이미지검색 API를 가져와보려고 한다.

Kakao Developer 공식문서

위 링크를 들어가서 보면

gradle, 권한

    //gson, retrofit
    implementation ("com.google.code.gson:gson:2.10.1")
    implementation ("com.squareup.retrofit2:retrofit:2.9.0")
    implementation ("com.squareup.retrofit2:converter-gson:2.9.0")
    implementation ("com.squareup.okhttp3:okhttp:4.10.0")
    implementation ("com.squareup.okhttp3:logging-interceptor:4.10.0")
    //
    <uses-permission android:name="android.permission.INTERNET"/>

키값 저장

이렇게 기본정보가 나와있다. search앞 /를 기준으로
https://dapi.kakao.com/v2/ 와 search/image로 나눠서 저장해준다.
다음으로 내 어플리케이션에 들어가 앱을 추가하고 REST API 키를 저장해둔다.

NetWorkInterface

공식문서에서 조금 아래로 내려보면 요청값에 헤더와 쿼리 파라미터가 있다. 이 값들을 이용해서 인터페이스를 만들어준다. 여기서 @GET()괄호 안에는 위에서 저장해둔 키값인 search/image를 넣어주면된다.

interface NetWorkInterface {
    @GET(Contract.REQUEST_ADDRESS)
    suspend fun getImage(
        @Header("Authorization") authHeader: String,
        @QueryMap param: HashMap<String, String>
    ): SearchResponse
}

데이터 받아오기

공식문서를 더 내려보면 응답 부분에 이렇게 있다. 이 값들을 이용해서 json파일을 gson으로 받아와준다. 이중에서 thumbnail_url, display_sitename, datetime 3가지 데이터를 가져와서 사용할 예정이다.

data class SearchResponse(
    @SerializedName("meta")
    val searchMeta: SearchMeta,
    @SerializedName("documents")
    val searchDocument: MutableList<SearchDocument>?
)

data class SearchMeta(
    val is_end: Boolean,
    val pageable_count: Int,
    val total_count: Int
)
data class SearchDocument(
    val collection: String,
    val datetime: String,
    val display_sitename: String,
    val doc_url: String,
    val height: Int,
    val image_url: String,
    val thumbnail_url: String,
    val width: Int
)

NetWorkClient

네트워크 클라이언트를 object로 만들어준다. 여기서 baseUrl에는 미리저장해둔 키인 https://dapi.kakao.com/v2/ 를 넣어주면 된다.

object NetWorkClient {

    private fun createOkHttpClient(): OkHttpClient {
        val interceptor = HttpLoggingInterceptor()

        if (BuildConfig.DEBUG)
            interceptor.level = HttpLoggingInterceptor.Level.BODY
        else
            interceptor.level = HttpLoggingInterceptor.Level.NONE

        return OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .addNetworkInterceptor(interceptor)
            .build()
    }

    private val imageRetrofit = Retrofit.Builder()
        .baseUrl(Contract.SERVICE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(createOkHttpClient())
        .build()

    val imageNetWork: NetWorkInterface = imageRetrofit.create(NetWorkInterface::class.java)

}

fragment

이 값들을 프레그먼트에서 받아와야한다.

    private fun communicateNetWork(param: HashMap<String, String>) = lifecycleScope.launch() {
        val authKey = "KakaoAK ${Contract.API_KEY}"
        val responseData = NetWorkClient.imageNetWork.getImage(authKey, param)
        items = responseData.searchDocument ?: mutableListOf()
        val adapter = SearchAdapter(items)

        adapter.itemClick = object : SearchAdapter.ItemClick{
            override fun onClick(item: SearchDocument, position: Int) {
                handleSelectedItem(item)
            }
        }

        binding.searchRecyclerView.adapter = adapter
        binding.searchRecyclerView.layoutManager = GridLayoutManager(context, 2)
    }
    ...
    private fun setUpImageParameter(input: String): HashMap<String, String> {
        val authKey = "KakaoAK ${Contract.API_KEY}" //REST API 키 넣어주기
        return hashMapOf(
            "Authorization" to authKey,
            "query" to input,
            "sort" to "recency",
            "page" to "1",
            "size" to "80"
        )
    }

위 함수들을 프레그먼트 안에서 사용해줄건데, edittext에 검색어를 입력하고, 확인버튼을 누르면 검색어를 가지고와서 리사이클러뷰에 띄워주기 위해서 버튼 클릭시에 선언해줬다.

searchImage.setOnClickListener {
    val searchEdit = searchEdit.text.toString()
    if (searchEdit.isNotBlank()) {
        val searchParam = setUpImageParameter(searchEdit)
        communicateNetWork(searchParam)
    }
}

kakaoAPI,kakaoapi,이미지검색

viewPager, tabLayout

뷰페이저2 + 텝레이아웃을 같이 적용시키는 방법

activity_main.xml

<androidx.viewpager2.widget.ViewPager2
	android:id="@+id/view_pager"
	android:layout_width="match_parent"
	android:layout_height="0dp"
	app:layout_constraintBottom_toTopOf="@+id/tab_layout"
	app:layout_constraintEnd_toEndOf="parent"
	app:layout_constraintStart_toStartOf="parent"
	app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.tabs.TabLayout
	android:id="@+id/tab_layout"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	app:layout_constraintBottom_toBottomOf="parent"
	app:layout_constraintEnd_toEndOf="parent"
	app:layout_constraintStart_toStartOf="parent" />

사용할 화면에 하단에 템레이아웃을, 화면전체에 뷰페이저를 만들어줬다.

Fragment1,2

이동할 프레그먼트를 hi,hihi라고 이름을 짓는다면, 그 안에서 companion object를 이용해서 newInstance를 만들어준다.

//프래그먼트1
companion object {
    fun newInstance() = hiFragment()
}
//프래그먼트2
companion object {
    fun newInstance() = hihiFragment()
}

MainTab

메인탭 데이터클래스를 만들어준다.

data class MainTab(
    val fragment:Fragment,
    @StringRes val title:Int
)

MainViewPagerAdapter

어뎁터를 만들어서 연결해준다. 리스트로 MainTab에 추가할 프래그먼트를 관리해주면 프래그먼트를 추가할때도 관리가 편해져서 이렇게 사용한다.

class MainViewPagerAdapter(
    fragmentActivity: FragmentActivity
) : FragmentStateAdapter(fragmentActivity) {

    private val fragments= listOf(
        MainTab(
            fragment = ImageSearchFragment.newInstance(),
            title = R.string.main_tab_search
        ),
        MainTab(
            fragment = KeepFragment.newInstance(),
            title = R.string.main_tab_keep
        )
    )
    override fun getItemCount(): Int = fragments.size
    override fun createFragment(position: Int): Fragment = fragments[position].fragment
    fun getTitle(position: Int): Int = fragments[position].title

}

MainActivity

먼저 뷰페이저를 선언해준다.

private val viewPagerAdapter by lazy {
    MainViewPagerAdapter(this@MainActivity)
}

그리고 어뎁터를 연결해준다.

private fun initView() = with(binding) {
    viewPager.adapter = viewPagerAdapter
    TabLayoutMediator(tabLayout, viewPager){ tab, position ->
        tab.setText(viewPagerAdapter.getTitle(position))
    }.attach()
}

이렇게 사용하면 화면에 viewPager와 TabLayout을 적용시킬 수 있다.
ViewPager, viewpager, viewPager, TabLayout, tablayout

키보드 숨김처리

private fun View.hideKeyboardInput() {
    val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    imm.hideSoftInputFromWindow(windowToken, 0)
}

위 함수를 원하는곳에서 불러주면 된다. 그냥부를때 -> hideKeyboardInput() 프래그먼트에서 부를때 -> binding.root.hideKeyboardInput()

키보드숨김처리,키보드숨김,키보드

profile
이우진

0개의 댓글