Issue
I am building an app that returns a list of Github Users from the api on the Main Activity
, and the detail of the selected user on the Detail User Activity
. When I run the app, the Main Activity
shows the list just fine using RecyclerView
, but when I pressed on one of the users, my app moves to that activity but won't show anything. Also in my Logcat, there's an error that says No adapters attached, skipping layout. Even though I don't have any RecyclerView
inside my detail activity.
Here's my MainActivity
:
package com.example.githubuser
import android.app.SearchManager
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.githubuser.databinding.ActivityMainBinding
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import androidx.appcompat.widget.SearchView
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val mainViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MainViewModel::class.java)
mainViewModel.listUsers.observe(this) { listUsers ->
val adapter = UsersAdapter(listUsers)
binding.rvUsers.adapter = adapter
val layoutManager = LinearLayoutManager(this)
binding.rvUsers.layoutManager = layoutManager
}
mainViewModel.isLoading.observe(this) {
showLoading(it)
}
}
private fun showUsers(listUsers: List<ItemsItem>) {
val adapter = UsersAdapter(listUsers)
binding.rvUsers.adapter = adapter
val layoutManager = LinearLayoutManager(this)
binding.rvUsers.layoutManager = layoutManager
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.option_menu, menu)
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchView = menu.findItem(R.id.search).actionView as SearchView
searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView.queryHint = resources.getString(R.string.search_hint)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(que: String): Boolean {
showLoading(true)
getUserSearchData(query = que)
searchView.clearFocus()
return true
}
override fun onQueryTextChange(newText: String): Boolean {
return false
}
})
return true
}
private fun getUserSearchData (query : String){
ApiConfig.getApiService().getUsers(query = query).enqueue(object : Callback<GithubResponse>{
override fun onResponse(
call: Call<GithubResponse>,
response: Response<GithubResponse>
) {
showLoading(false)
if (response.isSuccessful){
val filteredUsers = response.body()?.items?.filter { it.login.contains(query, true) }
showUsers(filteredUsers ?: emptyList())
}else{
Log.e("MainViewModel", "onFailure: ${response.message()}")
}
}
override fun onFailure(call: Call<GithubResponse>, t: Throwable) {
showLoading(false)
Log.d("TAG", "${t.message}")
}
})
}
private fun showLoading(isLoading: Boolean) {
binding.progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
}
}
Here's my UsersAdapter
:
package com.example.githubuser
import android.content.Intent
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class UsersAdapter(private var listUsers: List<ItemsItem>): RecyclerView.Adapter<UsersAdapter.MyViewHolder>() {
companion object {
const val EXTRA_USER = "user"
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int) =
MyViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.item_users, viewGroup, false))
override fun onBindViewHolder(myViewHolder: MyViewHolder, position: Int) {
val user = listUsers[position]
myViewHolder.tvUser.text = user.login
Glide.with(myViewHolder.ivUser)
.load(listUsers[position].avatarUrl)
.into(myViewHolder.ivUser)
myViewHolder.itemView.setOnClickListener {
val intent = Intent(myViewHolder.itemView.context, DetailUserActivity::class.java)
val userResponse = UserResponse(
gistsUrl = "",
reposUrl = "",
followingUrl = "",
createdAt = "",
login = user.login,
type = "",
blog = "",
subscriptionsUrl = "",
updatedAt = "",
siteAdmin = false,
company = "",
id = user.id,
publicRepos = 0,
gravatarId = "",
organizationsUrl = "",
starredUrl = "",
followersUrl = "",
publicGists = 0,
url = "",
receivedEventsUrl = "",
followers = 0,
avatarUrl = user.avatarUrl,
eventsUrl = "",
htmlUrl = "",
following = 0,
name = "",
location = "",
nodeId = ""
)
intent.putExtra(UsersAdapter.EXTRA_USER, userResponse)
intent.putExtra("photo", user.avatarUrl)
myViewHolder.itemView.context.startActivity(intent)
}
}
override fun getItemCount() = listUsers.size
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvUser: TextView = view.findViewById(R.id.tv_users)
val ivUser: ImageView = view.findViewById(R.id.iv_users)
}
}
And here's my DetailUserActivity
:
package com.example.githubuser
import DetailViewModel
import android.media.Image
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.bumptech.glide.Glide
import com.example.githubuser.UsersAdapter.Companion.EXTRA_USER
import com.example.githubuser.databinding.ActivityMainBinding
import org.w3c.dom.Text
class DetailUserActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var adapter: UsersAdapter
companion object {
const val EXTRA_NAME = "extra_name"
const val EXTRA_USERNAME = "extra_username"
const val EXTRA_FOLLOWERS = "extra_followers"
const val EXTRA_FOLLOWING = "extra_following"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val viewModel = ViewModelProvider(this)[DetailViewModel::class.java]
// adapter = UsersAdapter(ItemsItem)
val tv_name = findViewById<TextView>(R.id.name)
val avatar_user = findViewById<ImageView>(R.id.userPhoto)
val tv_username = findViewById<TextView>(R.id.username)
val tv_followers = findViewById<TextView>(R.id.followers)
val tv_following = findViewById<TextView>(R.id.following)
val user = intent.getParcelableExtra<UserResponse>("user_key")
val login = intent.getStringExtra(EXTRA_USERNAME)
if (login != null) {
viewModel.getDetailUser(login)
}
viewModel.userDetail.observe(this, Observer {
if (user != null){
showLoading(false)
Glide.with(this)
.load(user.avatarUrl)
.into(avatar_user)
tv_name.text = user.name
tv_username.text = user.login
// tv_company.text = user.company
// tv_location.text = user.location
tv_followers.text = user.followers.toString()
tv_following.text = user.following.toString()
}
})
}
private fun showLoading(isLoading: Boolean) {
binding.progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
}
}
I tried looking for this specific error on other questions but I can't seem to find an answer.
This is my stack trace error (note that I also have an additional warning about my Glide module at the end):
Solution
Maybe problem is your layout
private lateinit var binding: ActivityMainBinding
this line have in your Detail activity. it should be ActivityDetailBinding, or something else. You could try
And please post your stack trace error
Edit :
In your adapter, you put 2 extras to your intent:
intent.putExtra(UsersAdapter.EXTRA_USER, userResponse)
intent.putExtra("photo", user.avatarUrl)
myViewHolder.itemView.context.startActivity(intent)
BUT, in detail activity, you get value with wrong key:
val user = intent.getParcelableExtra<UserResponse>("user_key")
val login = intent.getStringExtra(EXTRA_USERNAME)
Since you are getting the user model from intent extras, You can update your UI with that data -
val user = intent.getParcelableExtra<UserResponse?>(UsersAdapter.EXTRA_USER)
if (user != null){
showLoading(false)
Glide.with(this)
.load(user.avatarUrl)
.into(avatar_user)
tv_name.text = user.name
tv_username.text = user.login
tv_followers.text = user.followers.toString()
tv_following.text = user.following.toString()
}
Answered By - ninhnau19
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.