Calling APIs directly from a view class violates the principle of separation of concerns. This flaw occurs when the responsibility of handling network communication and data-fetching logic is mixed with the UI-related tasks within the view class. It can lead to code that is difficult to maintain, test, and understand.
class FollowingFragment : Fragment() {
// Rest of the codes
private fun displayFollowing(username: String) {
showLoading(true)
Log.d(TAG, "displayFollowing: ")
val client = RetrofitConfig.getUserService().getUserFollowing(username)
client.enqueue(object : Callback<List<FollowingResponse>> {
override fun onResponse(
call: Call<List<FollowingResponse>>,
response: Response<List<FollowingResponse>>
) {
showLoading(false)
if (response.isSuccessful) {
val responseBody = response.body()
if (responseBody != null) setFollowing(responseBody)
Log.d(TAG, "onResponse: ${responseBody.toString()}")
} else {
Log.e(TAG, "onFailure: ${response.message()}")
}
}
override fun onFailure(call: Call<List<FollowingResponse>>, t: Throwable) {
showLoading(false)
Log.e(TAG, "onFailure: ${t.message}")
}
})
}
// Rest of the codes.
}
It is better to follow architectural patterns like MVVM (Model-View-ViewModel) or MVP (Model-View-Presenter). These patterns separate the UI logic from the data-fetching operations, improving code organization, testability, and maintainability.
FollowersFragment.kt
This code has the problem like in the FollowingFragment.kt.
class FollowersFragment : Fragment() {
// Rest of the codes
private fun displayFollowers(username: String) {
showLoading(true)
val client = RetrofitConfig.getUserService().getUserFollowers(username)
client.enqueue(object : Callback<List<FollowersResponse>> {
override fun onResponse(
call: Call<List<FollowersResponse>>,
response: Response<List<FollowersResponse>>
) {
showLoading(false)
if (response.isSuccessful) {
val responseBody = response.body()
if (responseBody != null) setFollowers(responseBody)
Log.d(TAG, "onResponse: ${responseBody.toString()}")
} else {
Log.e(TAG, "onFailure: ${response.message()}")
}
}
override fun onFailure(call: Call<List<FollowersResponse>>, t: Throwable) {
showLoading(false)
Log.e(TAG, "onFailure: ${t.message}")
}
})
// Rest of the codes.
}
MainActivity.kt
private fun searchUser() {
showLoading(true)
val client = RetrofitConfig.getUserService().getUsers(USERNAME)
client.enqueue(object : Callback<UserResponse> {
override fun onResponse(call: Call<UserResponse>, response: Response<UserResponse>) {
showLoading(false)
if (response.isSuccessful) {
val responseBody = response.body()
if (responseBody != null) {
setUser(responseBody.items)
}
} else {
Log.e(TAG, "onFailure: ${response.message()}")
}
}
override fun onFailure(call: Call<UserResponse>, t: Throwable) {
showLoading(false)
Log.e(TAG, "onFailure: ${t.message}")
}
})
}
Calling APIs directly from a view class violates the principle of separation of concerns. This flaw occurs when the responsibility of handling network communication and data-fetching logic is mixed with the UI-related tasks within the view class. It can lead to code that is difficult to maintain, test, and understand.
It is better to follow architectural patterns like MVVM (Model-View-ViewModel) or MVP (Model-View-Presenter). These patterns separate the UI logic from the data-fetching operations, improving code organization, testability, and maintainability.
This code has the problem like in the
FollowingFragment.kt
.