Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1692 connectés 

  FORUM HardWare.fr
  Programmation
  Android

  [kotlin] Passer un lambda via NavController.navigate

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[kotlin] Passer un lambda via NavController.navigate

n°2365905
matheo265
Posté le 29-10-2020 à 11:26:52  profilanswer
 

Bonjour,
 
J'ai créé un fragment générique qui se contente d'initialiser une vue (RecyclerView + Adapter). Les données de l'adapter sont récupérées via un webservice que j'attaque par l'intermédiaire de la librairie Volley.
 
Sur mon activité principale, j'utilise un NavController et la méthode navigate() afin de naviguer d'une page à une autre (mais toujours au travers du fragment générique). Lors de la navigation, j'envoi un paramètre "action" et un paramètre "id" qui permettront de spécifier auprès du webservice les données à récupérer.
 
Ce fonctionnement marche bien.
 
Seulement maintenant, il faut que je puisse faire des traitements spécifiques selon les pages où je me trouve. Dans mon fragment, j'ai donc déclaré une méthode "setOnTouch" que j'utilise pour initialiser l'événement qui se produira lorsque l'utilisateur touchera un élément de ma RecyclerView :
 

Code :
  1. class CustomAdapter() : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
  2.     private lateinit var onTouch: (result: JSONObject) -> Unit
  3.     [...]
  4.     fun setOnTouch(touchEvent: (result: JSONObject) -> Unit){
  5.         this.onTouch = touchEvent
  6.     }
  7.     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
  8.         val v: View = LayoutInflater.from(parent.context).inflate(mLayout, parent, false)
  9.         v.setOnClickListener { view ->
  10.             if (this::onTouch.isInitialized)
  11.                 if (view.tag is JSONObject) this.onTouch(view.tag as JSONObject)
  12.         }
  13.         return ViewHolder(v)
  14.     }
  15.     [...]
  16. }


 

Code :
  1. class DataListFragment(action: String, id: String): Fragment() {
  2.     private var ad = CustomAdapter(customLayout)
  3.     [...]
  4.     fun setOnTouch(clickEvent: (result: JSONObject) -> Unit){
  5.         this.ad.setOnTouch(clickEvent)
  6.     }
  7.     [...]
  8. }


 
Ma question est la suivante : comment passer une méthode (lambda) via la méthode navigate() :
 

Code :
  1. val bundle = Bundle()
  2. bundle.putString("action","clients" )
  3. bundle.putString("id","1234" )
  4. bundle.put?????? {result: JSONObject ->
  5.    //Traitement de l'enregistrement
  6. }
  7. findNavController(R.id.nav_host_fragment).navigate(R.id.nav_test, bundle)


 
J'ai essayé simplement ceci :
 

Code :
  1. bundle.putSerializable { result: JSONObject ->
  2. } as Serializable


 
Mais ça marche pas... J'ai essayé de créer une classe qui hérite de Bundle, pour créer une propriété "onTouch" mais impossible : la classe Bundle est déclarée par Google comme Final...  :heink:  
 
J'ai ensuite créé une data classe de type Parcelable :
 

Code :
  1. @Parcelize
  2. data class ListDataBundle(
  3.     var action: String,
  4.     var id: String,
  5.     var touchEvent: Serializable
  6. ) : Parcelable {}


 
Puis dans mon activité :
 

Code :
  1. bundle.putParcelable("data", ListDataBundle("clients","1234",{ result: JSONObject ->
  2. }  as Serializable))


 
Et dans mon fragment récupérer la fonction comme ceci :
 

Code :
  1. val monParcelable = this.arguments?.getParcelable("data" ) as ListDataBundle
  2. this.ad.setOnTouch(monParcelable.touchEvent as (result: JSONObject) -> Unit)


 
Mais à chaque fois j'ai cette fichue erreur "IOException writing serializable object"  :kaola:  qui, à mon avis, signifie qu'on ne peut pas sérialiser le type (result: JSONObject) -> Unit...
 
Je suis un peu à court d'idées... Certainement dû au fait que je débute en Kotlin et que je suis loin de maitriser encore les principaux concepts...
 
De l'aide ne serait pas de refus  :cry:

mood
Publicité
Posté le 29-10-2020 à 11:26:52  profilanswer
 

n°2366388
matheo265
Posté le 03-11-2020 à 08:49:56  profilanswer
 

Salut,
 
Continuant à analyser mon problème, j'ai cru comprendre que c'était l'argument de mon lambda (à savoir JSONObject) qui posait problème. Lorsque j'utilise :

Code :
  1. bundle.putParcelable(monDataListFragment)


Il va me sérialiser l'ensemble de mon objet et, lorsqu'il tombe sur mon type JSONObject, il ne sait pas faire car JSONObject n'est pas sérialisable...  :kaola:  
 
Sur le net, certains parlent de convertir le JSONObject en string dans l'objet, puis de le reconvertir en JSONObject par la suite. Mais je trouve ce fonctionnement particulièrement lourd.
 
De plus, mon objet utilise aussi des arguments de type View, et là : impossible de convertir en string...  :cry:

n°2366427
matheo265
Posté le 03-11-2020 à 15:07:18  profilanswer
 

Bon ben je me réponds encore à moi-même  :D  
 
J'ai trouvé une solution. En fait j'ai déclaré dans ma classe DataListFragment une interface :

Code :
  1. public interface DataListBundle {
  2.   fun touchEvent (action: String, result: JSONObject)
  3. }


J'ai ensuite fait hériter mon activité de cette interface afin d'y surcharger les méthodes qu'elle contient :

Code :
  1. override fun touchEvent(action: String, result: JSONObject) {
  2.    if (action=="clients" ){
  3.       //effectue un traitement dans le cas d'affichage de clients
  4.    } else if (action=="fournisseurs" ){
  5.       //effectue un autre type de traitement s'il s'agit de fournisseurs
  6.    }
  7. }


Et enfin, dans mon Adapter (auquel j'ai fourni le context de l'activité), j'ai juste à tester si le context hérite de mon interface DataListBundle :

Code :
  1. if (mContext is DataListFragment.DataListBundle){
  2.    (mContext as DataListFragment.DataListBundle).touchEvent(mAction,view.tag as JSONObject)
  3. }


Le tout fonctionne à merveille et ne me semble ni moche ni lourd  :jap:


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Android

  [kotlin] Passer un lambda via NavController.navigate

 

Sujets relatifs
[SQL] Comment passer de lignes par dates à des lignes par périodePasser les guillemets dans un SELECT Potgresql #%@* WTF !!
Comment passer une variable dans une fonction ??Passer au tour suivant boucle for each et probleme if
[Résolu PHP]aide pour passer de preg_replace à preg_replace_callback[C++] Lambda capture de pointeur
[résolu] git, passer des tag à master[Mongodb] Est il possible de passer un arbiter en secondary
Passer d'un tableau de byte en label une imagePasser de MySQL à MySQLi pour PHP 7
Plus de sujets relatifs à : [kotlin] Passer un lambda via NavController.navigate


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR