Project

09_mvvm : Network communication using retrofit - Search User Test

DevGoni 2021. 2. 23. 16:38
728x90

IRetrofit_Service에서 Coroutine으로 비동기 처리를 하기위해서 suspend 키워드를 추가

  @GET(API.SEARCH_USERS)
    suspend fun searchUsers(@Query("query") searchTerm : String) : JsonElement
    // 사용자 검색 서비스

 

 

Network와 통신해서 수신받은 data를 파싱하고 data class 타입의 ArrayList 담아 Bundle을 이용해 전달하기 위해서 User Class를 생성

data class User(var username: String, var profile_image: String) :Serializable
// Serializable을 상속받아 직렬화가 가능하도록 한다.

 

 

API에 사용자 검색에 대한 요청

//RetrofitManager.kt
//사용자검색 api 호출
    fun searchUsers(searchTerm: String?, completion: (RESPONSE_STATE, ArrayList<User>?) -> Unit) {
        val term = searchTerm.let { it } ?: ""

        mScope.launch {
            var parsedUserDataArray = ArrayList<User>()

            val job = launch(Dispatchers.IO) {
                val call =
                    iretrofitService?.searchUsers(searchTerm = term).let { it } ?: return@launch

                val body = call.asJsonObject
                val results = body.getAsJsonArray("results")
                val total = body.get("total").asInt

                Log.d(Constants.TAG, "${HomeViewModel::class.java.simpleName} " +
                        "/ message : ${total}")

                if (total != 0) {
                    // JsonArray result[] 내부의 JsonObject를 하나씩 받아 반복 수행
                    results.forEach { resultItem ->
                        val resultItemObject = resultItem.asJsonObject // get object

                        val username = resultItemObject.get("username").asString    // user -> username

                        val profile_image =
                            resultItemObject.get("profile_image").asJsonObject.get("small").asString
                            // object -> create_at

                        Log.d(Constants.TAG, "${HomeViewModel::class.java.simpleName} " +
                                "/ message : ${username}")

                        Log.d(Constants.TAG, "${HomeViewModel::class.java.simpleName} " +
                                "/ message : ${profile_image}")

                        val userItem = User(
                            username = username,
                            profile_image = profile_image,
                        )

                        parsedUserDataArray.add(userItem)
                        //ArrayList에 Photo 타입의 데이터를 추가가
                    }
                }
            }

            job.join()
            if(job.isCompleted){
                completion(RESPONSE_STATE.OK, parsedUserDataArray)
            }

        }

    }

 

 

Button 클릭 시 enum class의 SEARCH_TYPE 상수 값에 따라 사진, 사용자 검색 API를 호출하고 고차함수를 사용해 요청의 결과를 반환

// HomeActivty.kt
// SEARCH 버튼 이벤트
        binding.include.searchButton.setOnClickListener {
            Log.d(Constants.TAG, "HomeActivity SEARCH 버튼 클릭 - currentSearchType : ${currentSearchType}")

            handleSearchButton()    // 프로그래스바 활성화

            //검색 api 호출
            val userSearchInput = binding.searchEditText.text.toString()

            if(currentSearchType == SEARCH_TYPE.PHOTO){
                Log.d(Constants.TAG, "HomeActivity api 사진 검색 요청")

                //검색 api 호출
                RetrofitManager.instance.searchPhotos(searchTerm = userSearchInput, completion = {
                        response_state, responsePhotoArrayList ->
                    // responsePhotoArrayList : RetrofitManager.kt에서 Parsing한 Photo타입의 ArrayList

                    when(response_state){
                        RESPONSE_STATE.OK -> {
                            Log.d(Constants.TAG, "HomeActivity api 호출 성공 : ${responsePhotoArrayList?.size}")


                            val intent = Intent(this, CollectionActivity::class.java)
                            val bundle = Bundle()
                            bundle.putSerializable("photo_array_list", responsePhotoArrayList)
                            //bundle은 Parcelable 객체를 상속받아 구현된 직렬화 class로, bundle 객체는 내부적으로 HashMap을 사용하며,
                            // Parcelable로 구현되어 있어 간단한 데이터 전달에 유용하다.
                            // putSerializable()을 이용하면 객체가 Serialzable을 상속받고 있다면 객체를 보낼 수 있다.
                            // 직렬화 : 객체를 바이트 스트림으로 바꾸어, 객체에 저장된 데이터를 스트림에 쓰기위해 연속적인 serial 데이터로 변환
                            intent.putExtra("array_bundle", bundle)
                            //intent.putExtra()로 해당 번들을 넣는다.
                            intent.putExtra("searchTerm", userSearchInput)
                            // 사용자가 입력한 입력값(AppBar의 Title로 사용)
                            startActivity(intent)

                        }
                        RESPONSE_STATE.FAIL -> {
                            Log.d(Constants.TAG, "HomeActivity api 호출 실패 : ${responsePhotoArrayList}")
                        }
                        RESPONSE_STATE.NONE -> {
                            Toast.makeText(this, getString(R.string.No_search_results), Toast.LENGTH_SHORT).show()
                            binding.searchEditText.setText("")
                            //검색 결과가 없을 때만 검색창 초기화
                        }
                    }

                    handleSearchButton()
                    // 프로그래스바 비활성화
                })


            }else if(currentSearchType == SEARCH_TYPE.USER){
                Log.d(Constants.TAG, "HomeActivity api 사용자 검색 요청")

                RetrofitManager.instance.searchUsers(searchTerm = userSearchInput, completion = {
                        response_state, responseUserArrayList ->
                    // responsePhotoArrayList : RetrofitManager.kt에서 Parsing한 Photo타입의 ArrayList

                    when(response_state){
                        RESPONSE_STATE.OK -> {
                            Log.d(Constants.TAG, "HomeActivity api 호출 성공 : ${responseUserArrayList?.size}")


                           /*
                            val intent = Intent(this, CollectionActivity::class.java)
                            val bundle = Bundle()
                            bundle.putSerializable("user_array_list", responseUserArrayList)
                            //bundle은 Parcelable 객체를 상속받아 구현된 직렬화 class로, bundle 객체는 내부적으로 HashMap을 사용하며,
                            // Parcelable로 구현되어 있어 간단한 데이터 전달에 유용하다.
                            // putSerializable()을 이용하면 객체가 Serialzable을 상속받고 있다면 객체를 보낼 수 있다.
                            // 직렬화 : 객체를 바이트 스트림으로 바꾸어, 객체에 저장된 데이터를 스트림에 쓰기위해 연속적인 serial 데이터로 변환
                            intent.putExtra("array_bundle", bundle)
                            //intent.putExtra()로 해당 번들을 넣는다.
                            intent.putExtra("searchTerm", userSearchInput)
                            // 사용자가 입력한 입력값(AppBar의 Title로 사용)
                            startActivity(intent)
                            */

                        }
                        RESPONSE_STATE.FAIL -> {
                            Log.d(Constants.TAG, "HomeActivity api 호출 실패 : ${responseUserArrayList}")
                        }
                        RESPONSE_STATE.NONE -> {
                            Toast.makeText(this, getString(R.string.No_search_results), Toast.LENGTH_SHORT).show()
                            binding.searchEditText.setText("")
                            //검색 결과가 없을 때만 검색창 초기화
                        }
                    }

                    handleSearchButton()
                    // 프로그래스바 비활성화
                })

            }

        }