Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.3k views
in Technique[技术] by (71.8m points)

I'm stuck, i can't pass data from model with api Rest, into another activity

I don't know why it's says me that "java.lang.IndexOutOfBoundsException: Index: 0, Size: 0" I've been searching for this since 2 hours, and i don't know why there is this problem now, can you help me ? I want to pass data from apiRest into another activity with intent and putExtra/getExtra (I will do with firebase later, more simple and more easy way).

Main Activity

package com.mehdi.myapplication

class MainActivity : AppCompatActivity(), ListAdapter.OnItemClickListener {

lateinit var userAdapter: ListAdapter
var lm = LinearLayoutManager(this)
private val users: MutableList<Results> = mutableListOf()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    initView()
    getClassApiRet()

}
override fun onItemClick(position: Int) {
    Toast.makeText(this, position.toString(), Toast.LENGTH_LONG).show()
    val intent = Intent(this, DetailPageActivity::class.java)
    intent.putExtra("email", users[position].email)
    startActivity(intent)
}

fun initView() {
    UserRecycleView.layoutManager = lm
    userAdapter = ListAdapter(this, this)
    UserRecycleView.adapter = userAdapter

}

fun getClassApiRet() {
    val retro = Instance().getRetroInstance().create(ClassApiRest::class.java)
    retro.getData().enqueue(object : Callback<ClassApi> {
        override fun onResponse(call: Call<ClassApi>, response: Response<ClassApi>) {
            val users = response.body()
            runOnUiThread {
                userAdapter.setUsers(users?.results!!)
            }
        }
        override fun onFailure(call: Call<ClassApi>, t: Throwable) {
            Log.e("Failed", t.message.toString())
        }
    })
}
}

UserInfo

    class ClassApi {

    @SerializedName("results")
    @Expose
    val results: List<Results>? = null

}

class Results {

    @SerializedName("name")
    @Expose
    val name: Name? = null

    @SerializedName("email")
    @Expose
    val email: String? = null

    @SerializedName("login")
    @Expose
    val login: Login? = null

    @SerializedName("picture")
    @Expose
    val picture: Picture? = null

}

class Name {

    @SerializedName("title")
    @Expose
    val title: String? = null

    @SerializedName("first")
    @Expose
    val first: String? = null

    @SerializedName("last")
    @Expose
    val last: String? = null

}

class Login {

    @SerializedName("username")
    @Expose
    val username: String? = null

}

class Picture {

    @SerializedName("medium")
    @Expose
    val medium: String? = null

    @SerializedName("large")
    @Expose
    val large: String? = null

}

ListAdapter

    class ListAdapter(val context: Context, val listener: OnItemClickListener): RecyclerView.Adapter<ListAdapter.UsersViewHolder>() {

    private val users: MutableList<Results> = mutableListOf()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListAdapter.UsersViewHolder {
        return UsersViewHolder(LayoutInflater.from(context).inflate(R.layout.row_user_list, parent, false))
    }

    override fun onBindViewHolder(holder: ListAdapter.UsersViewHolder, position: Int) {
        holder.bindModel(users[position])
    }

    override fun getItemCount(): Int {
        return users.size
    }

    fun setUsers(results: List<Results>) {
        users.clear()
        users.addAll(results)
        notifyDataSetChanged()
    }

    inner class UsersViewHolder(item: View) : RecyclerView.ViewHolder(item), View.OnClickListener {

        val UserImage: CircleImageView = item.findViewById(R.id.UserImage)
        val UserName: TextView = item.findViewById(R.id.UserName)
        val UserPseudo: TextView = item.findViewById(R.id.UserPseudo)

        init {
            itemView.setOnClickListener(this)
        }

        fun bindModel(b: Results) {

            UserName.text = b.name?.first
            UserPseudo.text = b.login?.username

            val url = b.picture?.medium
            Glide.with(UserImage)
                .load(url)
                .placeholder(R.drawable.ic_launcher_background)
                .error(R.drawable.ic_launcher_background)
                .fallback(R.drawable.ic_launcher_foreground)
                .into(UserImage)
        }

        override fun onClick(v: View?) {
            val position = adapterPosition
            if (position != RecyclerView.NO_POSITION) {
                listener.onItemClick(position)
            }
        }
    }
    interface OnItemClickListener {
        fun onItemClick(position: Int)
    }
}

Edit !!!

I think the probleme is with the position and the interface, he can't get data.

ListAdapter

override fun onClick(v: View?) {
        val position = adapterPosition
        if (position != RecyclerView.NO_POSITION) {
            listener.onItemClick(position)
        }
    }
}
interface OnItemClickListener {
    fun onItemClick(position: Int)
}

Main Activity

override fun onItemClick(position: Int) {
    Toast.makeText(this, users[position].email.toString(), Toast.LENGTH_LONG).show()
    val intent = Intent(this, DetailPageActivity::class.java)
    //intent.putExtra("lolipop", users[position].toString())
    startActivity(intent)
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your response listener is passing the list of users to the ListAdapter, but it doesn't do anything to the MainActivity's users property, so that list remains empty. Then your item click listener tries to access the user by index in that empty list.

I would remove the users property from the Activity since there is no practical use for it. In your ListAdapter, change the onItemClick function of the OnItemClickListener to pass the actual User instead of the User's position in the data. You can get the actual User using the adapterPosition from within the adapter, since it owns the users list.

Edit: I'm suggesting to change your listener function signature to return an item directly. There's no reason the Activity should have to find the item in the collection when the Adapter can just provide it directly.

// ListAdapter:

override fun onClick(v: View?) {
    listener.onItemClick(users[adapterPosition])
}

interface OnItemClickListener {
    fun onItemClick(results: Results)
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...