IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Kotlin Discussion :

Passer un lambda via NavController.navigate


Sujet :

Kotlin

  1. #1
    Membre régulier Avatar de windmastr26
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2009
    Messages
    234
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2009
    Messages : 234
    Points : 108
    Points
    108
    Par défaut Passer un lambda via NavController.navigate
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class CustomAdapter() : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
        private lateinit var onTouch: (result: JSONObject) -> Unit
     
        [...]
     
        fun setOnTouch(touchEvent: (result: JSONObject) -> Unit){
            this.onTouch = touchEvent
        }
     
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val v: View = LayoutInflater.from(parent.context).inflate(mLayout, parent, false)
            v.setOnClickListener { view ->
                if (this::onTouch.isInitialized)
                    if (view.tag is JSONObject) this.onTouch(view.tag as JSONObject)
            }
            return ViewHolder(v)
        }
     
        [...]
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class DataListFragment(action: String, id: String): Fragment() {
        private var ad = CustomAdapter(customLayout)
        [...]
     
        fun setOnTouch(clickEvent: (result: JSONObject) -> Unit){
            this.ad.setOnTouch(clickEvent)
        }
        [...]
    }
    Ma question est la suivante : comment passer une méthode (lambda) via la méthode navigate() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    val bundle = Bundle()
    bundle.putString("action","clients")
    bundle.putString("id","1234")
    bundle.put?????? {result: JSONObject ->
       //Traitement de l'enregistrement
    }
    findNavController(R.id.nav_host_fragment).navigate(R.id.nav_test, bundle)
    J'ai essayé simplement ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bundle.putSerializable { result: JSONObject ->
    } 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...

    J'ai ensuite créé une data classe de type Parcelable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    @Parcelize
    data class ListDataBundle(
        var action: String,
        var id: String,
        var touchEvent: Serializable
    ) : Parcelable {}
    Puis dans mon activité :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bundle.putParcelable("data", ListDataBundle("clients","1234",{ result: JSONObject ->
    }  as Serializable))
    Et dans mon fragment récupérer la fonction comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    val monParcelable = this.arguments?.getParcelable("data") as ListDataBundle
    this.ad.setOnTouch(monParcelable.touchEvent as (result: JSONObject) -> Unit)
    Mais à chaque fois j'ai cette fichue erreur "IOException writing serializable object" 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

  2. #2
    Membre régulier Avatar de windmastr26
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2009
    Messages
    234
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2009
    Messages : 234
    Points : 108
    Points
    108
    Par défaut
    Bon ben je me réponds à moi-même

    J'ai trouvé une solution. En fait j'ai déclaré dans ma classe DataListFragment une interface :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public interface DataListBundle {
      fun touchEvent (action: String, result: JSONObject)
    }
    J'ai ensuite fait hériter mon activité de cette interface afin d'y surcharger les méthodes qu'elle contient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    override fun touchEvent(action: String, result: JSONObject) {
       if (action=="clients" ){
          //effectue un traitement dans le cas d'affichage de clients
       } else if (action=="fournisseurs" ){
          //effectue un autre type de traitement s'il s'agit de fournisseurs
       }
    }
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (mContext is DataListFragment.DataListBundle){
       (mContext as DataListFragment.DataListBundle).touchEvent(mAction,view.tag as JSONObject)
    }
    Le tout fonctionne à merveille et ne me semble ni moche ni lourd

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Passer deux variables via une URL
    Par 123quatre dans le forum Langage
    Réponses: 8
    Dernier message: 28/06/2007, 19h02
  2. Faire passer des arguments via window.open()
    Par juanqui dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 22/02/2007, 19h27
  3. PHP Passer une variable via une liste deroulante
    Par lepierre dans le forum Langage
    Réponses: 3
    Dernier message: 20/10/2006, 12h09
  4. [VB]Passer un paramètre via executable et le récupérer
    Par ironik dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 29/03/2006, 14h36
  5. Volume de données maximum à passer dans Excel via delphi?
    Par batounet dans le forum Bases de données
    Réponses: 2
    Dernier message: 24/03/2006, 20h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo