0
I’m looking to do a search on the Github API using Kotlin Coroutines in a different thread than the main one, but by receiving the values, it’s generating this error:
021-01-27 19:50:22.961 17831-17831/com.posart.githubinfo E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.posart.githubinfo, PID: 17831
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.posart.githubinfo.network.UserNetwork.getFollowers()' on a null object reference
at com.posart.githubinfo.views.details.DetailsFragment$onCreateView$1.onChanged(DetailsFragment.kt:47)
at com.posart.githubinfo.views.details.DetailsFragment$onCreateView$1.onChanged(DetailsFragment.kt:17)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:131)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:149)
at androidx.lifecycle.LiveData.setValue(LiveData.java:307)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at androidx.lifecycle.LiveData$1.run(LiveData.java:91)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7562)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
I’m not sure how to use the corroding, but I think the problem isn’t exactly in their use. I think when the fragment gets the variable data, the API search hasn’t been done yet. I’ll put here the files I think may be associated with the error:
Repository
class UserRepository {
fun getUser(username: String): LiveData<UserNetwork> {
val userResponse = MutableLiveData<UserNetwork>()
GitHubApi().getUser(username).enqueue(object : Callback<UserNetwork> {
override fun onFailure(call: Call<UserNetwork>, t: Throwable) {
userResponse.value = null
}
override fun onResponse(call: Call<UserNetwork>, response: Response<UserNetwork>) {
if (response.isSuccessful) {
userResponse.value = response.body()
} else {
userResponse.value = null
}
}
})
return userResponse
}
fun getUserRepos(username: String): LiveData<List<RepoNetwork>> {
val reposResponse = MutableLiveData<List<RepoNetwork>>()
GitHubApi().getReposUser(username).enqueue(object : Callback<List<RepoNetwork>> {
override fun onFailure(call: Call<List<RepoNetwork>>, t: Throwable) {
reposResponse.value = null
}
override fun onResponse(
call: Call<List<RepoNetwork>>,
response: Response<List<RepoNetwork>>
) {
if (response.isSuccessful) {
reposResponse.value = response.body()
} else {
reposResponse.value = null
}
}
})
return reposResponse
}
}
Viewmodel
class DetailsViewModel(private val username: String) : ViewModel() {
private val _user = MutableLiveData<UserNetwork>()
val user: LiveData<UserNetwork>
get() = _user
private val _reposUser = MutableLiveData<List<RepoNetwork>>()
val reposUser: LiveData<List<RepoNetwork>>
get() = _reposUser
init {
viewModelScope.launch {
withContext(Dispatchers.IO) {
_user.postValue(UserRepository().getUser(username).value)
_reposUser.postValue(UserRepository().getUserRepos(username).value)
}
}
}
class Factory(private val username: String) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(DetailsViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return DetailsViewModel(username) as T
}
throw IllegalArgumentException("Unable to construct viewmodel")
}
}
}
Fragment
class DetailsFragment : Fragment() {
private lateinit var viewModel: DetailsViewModel
private fun adapterOnClick(repository: RepoNetwork) {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(repository.html_url)
startActivity(intent)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DetailsFragmentBinding.inflate(inflater)
val arguments =
DetailsFragmentArgs.fromBundle(
requireArguments()
)
val factory = DetailsViewModel.Factory(arguments.username)
viewModel = ViewModelProvider(this, factory).get(DetailsViewModel::class.java)
binding.viewModel = viewModel
binding.lifecycleOwner = this
viewModel.user.observe(viewLifecycleOwner, Observer {
binding.followersAndFollowing.text = getString(
R.string.followers_and_following,
it.followers, it.following
)
})
viewModel.reposUser.observe(viewLifecycleOwner, Observer {
binding.recyclerViewList.adapter = ReposAdapter(it) {
repository -> adapterOnClick(repository)
}
})
return binding.root
}
}
Apparently the code works, it would need to run the project on A.S to know the exact point that triggers the exception. If you were on Github it would be a lot easier to help.
– Diego Farias
I already managed to fix the bug. Thanks for your help
– Artur Bruno