728x90

카카오톡 검색 이미지

Api 연결 

 

dependencies

    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")

 

ImageSearchApi 

import com.example.imagesearch.data.ImageSearch
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query

private const val AUTH_HEADER = //API//
private const val SORT_DEFAULT = "accuracy"
private const val PAGE_NUMBER = 1
private const val API_MAX_RESULT = 80
interface ImageSearchApi {
    @GET("/v2/search/image")
    suspend fun getImage(
        @Header("Authorization") authorization: String = AUTH_HEADER,
        @Query("query") query: String,
        @Query("sort") sort: String = SORT_DEFAULT,
        @Query("page") page: Int = PAGE_NUMBER,
        @Query("size") size: Int = API_MAX_RESULT
    ): ImageSearch
}

 

RetrofitInstance

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitInstance {
    private const val BASE_URL = "https://dapi.kakao.com"
    private val retrofit by lazy {
        Retrofit
            .Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    val imageSearchApi: ImageSearchApi by lazy {
        retrofit.create(ImageSearchApi::class.java)
    }
}

DataDTO 

data class ImageSearch(
    val documents: MutableList<Document>,
    val meta: Meta
)

data class Document(
    val collection: String,
    @SerializedName("datetime")
    val datetime: String,
    @SerializedName("display_sitename")
    val displaySiteName: String,
    @SerializedName("doc_url")
    val docUrl: String,
    val height: Int,
    @SerializedName("image_url")
    val imageUrl: String,
    @SerializedName("thumbnail_url")
    val thumbnailUrl: String,
    val width: Int
)

data class Meta(
    @SerializedName("is_end")
    val isEnd: Boolean,
    @SerializedName("pageable_count")
    val pageableCount: Int,
    @SerializedName("total_count")
    val totalCount: Int
)

 

 

SearchImageFragment에서 사용 

package com.example.imagesearch.fragment

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.core.content.edit
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import com.example.imagesearch.adapter.ImageAdapter
import com.example.imagesearch.data.Document
import com.example.imagesearch.databinding.FragmentSearchImageBinding
import com.example.imagesearch.listener.ImageClickListener
import com.example.imagesearch.manager.DocumentsManager
import com.example.imagesearch.retrofit.RetrofitInstance
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class SearchImageFragment : Fragment(), ImageClickListener {
    private var _binding: FragmentSearchImageBinding? = null
    private val binding get() = _binding!!
    private lateinit var imageAdapter: ImageAdapter
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentSearchImageBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        with(binding) {
            btnSearch.setOnClickListener {
                val query = etSearch.text.toString()
                if (query.isEmpty()) return@setOnClickListener
                saveData(query)//검색어 저장

                //Api 연결 시 IO 으로 연결 하고, UI갱신은 withContext로 Main에서 처리
                CoroutineScope(Dispatchers.IO).launch {
                    val responseData = RetrofitInstance.imageSearchApi.getImage(query = query)
                    DocumentsManager.addDocument(responseData.documents)
                    withContext(Dispatchers.Main) {
                        initRecyclerView()
                    }
                }

                downKeyBoard(requireContext(), etSearch)
            }
        }
    }

    private fun initRecyclerView() {
        binding.recyclerView.apply {
            imageAdapter = ImageAdapter(this@SearchImageFragment)
            adapter = imageAdapter
            layoutManager = GridLayoutManager(context, 2)
            //검색 결과 80개 표시
            val searchList = DocumentsManager.getDocument()
            val sublist = if (searchList.size > 80) searchList.subList(0, 80) else searchList
            imageAdapter.submitList(sublist)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }

    //이미지 클릭시 좋아요 표시
    override fun onClickImage(document: Document, position: Int) {
        DocumentsManager.toggleLike(document)
        imageAdapter.notifyItemChanged(position)
    }

    //키보드 내리기
    private fun downKeyBoard(context: Context, editText: EditText) {
        val inputMethodManager =
            context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        editText.clearFocus()
        inputMethodManager.hideSoftInputFromWindow(editText.windowToken, 0)
    }

    //검색어 저장
    private fun saveData(keyWord: String) {
        activity?.getSharedPreferences(SEARCH_WORD, Context.MODE_PRIVATE)?.edit {
            putString(KEYWORD, keyWord)
            apply()
        }
    }

    //저장된 검색어 가져오기
    private fun getData() {
        val saveKeyWord = activity?.getSharedPreferences(SEARCH_WORD, Context.MODE_PRIVATE)
        binding.etSearch.setText(saveKeyWord?.getString(KEYWORD, ""))
    }

    override fun onResume() {
        getData()
        initRecyclerView()
        super.onResume()
    }

    companion object {
        private const val SEARCH_WORD = "searchWord"
        private const val KEYWORD = "keyWord"
    }
}

+ Recent posts