1

I am creating an app for my students. I am a teacher and hobby developer. Therefore, I need help. With three fragments, I successively create the name of the class, and the data of the student(first Name, last Name,..) then I attribute evaluation data to him. Everything works correctly. Except when I post all my students in the class in different groups. I end up with a student of the same name each time I validate the assessment for a new student. So over time, I'm going to end up with the same student 30 times in this display. I don't understand where the problem comes from. thank you for guiding me.

here is my code to add a student:

class AddFragment : androidx.fragment.app.Fragment() {

    private lateinit var  mUserViewModel: UserViewModel
    private lateinit var mEvalViewModel : EvalViewModel
    private lateinit var mUserEvalViewModel: UserEvalViewModel
    private val args by navArgs<AddFragmentArgs>()
    //Pour accéder au fab
    private var _binding: FragmentAddBinding? = null
    private val binding get() = _binding!!


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentAddBinding.inflate(inflater, container,false)
        val view = binding.root
        mUserViewModel = ViewModelProvider(this).get(UserViewModel::class.java)
        mEvalViewModel = ViewModelProvider(this).get(EvalViewModel::class.java)
        mUserEvalViewModel = ViewModelProvider(this).get(UserEvalViewModel::class.java)

        binding.addNameGroupEt.setText(args.currentGru.nameGroupG)
        binding.btnAddFragmentAdd.setOnClickListener {
            insertDataToDatabase()
            soundClic()
        }

        return view
    }

    private fun insertDataToDatabase() {
        val idUser = 0
        val firstName = binding.addFirstNameEt.text.toString()
        val lastName = binding.addLastNameEt.text.toString()
        val nbTeam = binding.addNumberTeamEt.text.toString()
        val gru_id_reference = args.currentGru.idGroup

        if(inputCheck(firstName, lastName, nbTeam)){
            //Create User OBject
            val user = User(idUser, args.currentGru.nameGroupG,  firstName, lastName, nbTeam, gru_id_reference)
            //Add Data to Database
            mUserViewModel.addUser(user)
            val action = AddFragmentDirections.actionAddFragmentToAddEvalFragment(user)
            findNavController().navigate(action)
            Toast.makeText(requireContext(), "Ajout réussi !", Toast.LENGTH_SHORT).show()
        }else{
            Toast.makeText(requireContext(), "Veuillez remplir tous les champs, SVP !", Toast.LENGTH_LONG).show()
        }
    }

    private fun inputCheck(firstName: String, lastName: String, nbTeam: String): Boolean{
        return !( TextUtils.isEmpty(firstName) && TextUtils.isEmpty(lastName) && TextUtils.isEmpty(nbTeam))
    }

    private fun soundClic() {
        val mediaPlayer: MediaPlayer = MediaPlayer.create(context, R.raw.select_click)
        mediaPlayer.start()
    }
}

Then i arrive on my code to add Evaluation for my student:

here the code to addEvalFragment:

class AddEvalFragment  : androidx.fragment.app.Fragment() {

    private lateinit var  mUserViewModel: UserViewModel
    private lateinit var mEvalViewModel : EvalViewModel
    private lateinit var mUserEvalViewModel: UserEvalViewModel
    private val args by navArgs<AddEvalFragmentArgs>()
    private var _binding: FragmentAddEvalBinding? = null
    private val binding get() = _binding!!


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentAddEvalBinding.inflate(inflater, container,false)
        val view = binding.root
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val adapter = AddEvalAdapter()
        val recyclerView = view.findViewById<RecyclerView>(R.id.recyclerview)
        recyclerView?.adapter = adapter
        recyclerView?.layoutManager = LinearLayoutManager(requireContext())

        mUserViewModel = ViewModelProvider(this).get(UserViewModel::class.java)
        mEvalViewModel = ViewModelProvider(this).get(EvalViewModel::class.java)
        mUserEvalViewModel = ViewModelProvider(this).get(UserEvalViewModel::class.java)

        mUserViewModel.getOneUser(args.currentUser.firstName, args.currentUser.lastName, args.currentUser.nameGroup)?.observe(viewLifecycleOwner, Observer {
            user ->
            user.let {
                adapter.setDataOneUser(user)
            }
        })
    }
}

and the code of my addEvalAdapter:

class AddEvalAdapter: RecyclerView.Adapter<AddEvalAdapter.MyViewHolder>() {

    private lateinit var context: Context
    var userList = emptyList<User>()

    class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        context = parent.context
        return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_row_add_eval, parent, false))
    }

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

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val currentItem = userList[position]

        holder.itemView.findViewById<TextView>(R.id.firstName_txt_Add_Eval).text = currentItem.firstName
        holder.itemView.findViewById<TextView>(R.id.lastName_txt_Add_Eval).text = currentItem.lastName
        holder.itemView.findViewById<TextView>(R.id.numeroTeam_txt_Add_Eval).text = currentItem.nbTeam

        holder.itemView.findViewById<Button>(R.id.btn_start_eval_Add_Eval).setOnClickListener {
            val eval = Eval(
                idEval = currentItem.id, note_seize = "0", note_douze = "0",
                note_relation = "0", note_trajets = "0", note_moteur = "0", note_emotion = "0", note_afl2 = "0", note_afl3 = "0",
                note_sur_vingt = "0", user_id_reference = currentItem.id)
            EvalViewModel(application = Application()).addEval(eval)
            Toast.makeText(context, "Bravo !", Toast.LENGTH_SHORT).show()
            soundClic()
            val action =
                AddEvalFragmentDirections.actionAddEvalFragmentToListMultipleTeam(Gru(currentItem.gru_id_reference, currentItem.nameGroup))
            holder.itemView.findNavController().navigate(action)
            soundClic()
        }
    }



    private fun soundClic() {
        val mediaPlayer: MediaPlayer = MediaPlayer.create(context, R.raw.select_click)
        mediaPlayer.start()
    }

    fun setDataOneUser(user: List<User>){
        this.userList = user
        notifyDataSetChanged()
    }
}

And my code to display the students. It's here who see multiple of the same student.

Here the code:

class MultipleAdapter: RecyclerView.Adapter<MultipleAdapter.MyViewHolder>() {
    var userList = emptyList<User>()

    private lateinit var context: Context

    class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        context = parent.context
        return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_row_multiple, parent, false))
    }

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

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val currentItem = userList[position]

        holder.itemView.findViewById<Button>(R.id.btn_start_eval_multiple).isVisible = true
        holder.itemView.findViewById<TextView>(R.id.firstName_txt_multiple).text = currentItem.firstName
        holder.itemView.findViewById<TextView>(R.id.lastName_txt_multiple).text = currentItem.lastName

            holder.itemView.findViewById<Button>(R.id.btn_start_eval_multiple).setOnClickListener {
                val action = MultipleFragmentDirections.actionMultipleFragmentToEvalFragment(User(currentItem.id, currentItem.nameGroup, currentItem.firstName, currentItem.lastName, currentItem.nbTeam, currentItem.gru_id_reference))
                holder.itemView.findNavController().navigate(action)
                soundClic()
            }
    }

    private fun soundClic() {
        val mediaPlayer: MediaPlayer = MediaPlayer.create(context, R.raw.select_click)
        mediaPlayer.start()
    }

    fun setDataMultiple(user: List<User>){
        this.userList = user
        notifyDataSetChanged()
    }
}

Here my query of to display my student on the multiplefragment:

@Query("SELECT * FROM user_table JOIN eval_table WHERE gru_id_reference LIKE :gru_id AND nbTeam LIKE :nbTeam  ORDER BY lastName ASC")
    fun retrieveUserWithNameGroup( gru_id: Int, nbTeam: String): LiveData<List<User>> 
Ahmed Hosny
  • 370
  • 4
  • 16
Wowocode
  • 23
  • 3

1 Answers1

0

I don't understand where the problem comes from.

I believe that your issue is that the query SELECT * FROM user_table JOIN eval_table WHERE gru_id_reference LIKE :gru_id AND nbTeam LIKE :nbTeam ORDER BY lastName ASC will result in the cartesian product, that is a row for every combination of user and eval.

So if user X has 10 evals then there will be 10 rows and hence 10 of that User in the List and so on.

MikeT
  • 51,415
  • 16
  • 49
  • 68
  • Your answer was just! I encounter two options. The first solution was to delete my eval_table of my query. The second solution was that my query was declared on UserViewModel and not in my UserEvalViewModel to conserve my original query. Thanks you so much for your help – Wowocode Aug 30 '22 at 19:09