{"id":3884,"date":"2022-06-01T15:12:56","date_gmt":"2022-06-01T13:12:56","guid":{"rendered":"http:\/\/blogperso.union31.fr\/?p=3884"},"modified":"2022-12-27T11:16:35","modified_gmt":"2022-12-27T10:16:35","slug":"kotlin-prise-de-notes","status":"publish","type":"post","link":"https:\/\/blogperso.union31.fr\/?p=3884","title":{"rendered":"KOTLIN : Prise de notes"},"content":{"rendered":"\n<p>En cours de r\u00e9daction<\/p>\n\n\n\n<p>Cours Google sur Kotlin avec Android: <a href=\"https:\/\/developer-android-com.translate.goog\/courses\/pathways\/compose?_x_tr_sl=auto&amp;_x_tr_tl=fr&amp;_x_tr_hl=fr\" target=\"_blank\" rel=\"noreferrer noopener\">lien<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Sommaire<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Classes\" >Classes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Constructeur\" >Constructeur<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Heritage\" >H\u00e9ritage<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Singleton\" >Singleton<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Fonctions\" >Fonctions<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Declaration\" >D\u00e9claration<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Lancer_une_activite_et_passage_de_parametres\" >Lancer une activit\u00e9 et passage de param\u00e8tres<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Log\" >Log<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Thread_coroutine_channel_et_autre\" >Thread, coroutine, channel et autre<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_recuperer_le_contexte_de_lapplication\" >Compose : r\u00e9cup\u00e9rer le contexte de l&rsquo;application<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_mise_en_forme_generale\" >Compose : mise en forme g\u00e9n\u00e9rale<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_LazyColumn_ou_LazyRow_et_Item_Divider\" >Compose : LazyColumn ou LazyRow (et Item, Divider)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_Card\" >Compose : Card<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_SnackBarHost_equivalent_a_Toast\" >Compose : SnackBarHost (\u00e9quivalent \u00e0 Toast)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_EditText\" >Compose : EditText<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_bouton_Button_OutlinedButton_TextButton\" >Compose : bouton (Button, OutlinedButton, TextButton)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_TopAppBar\" >Compose : TopAppBar<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_AlertDialog\" >Compose : AlertDialog<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_Ressource_Texte_Image_Couleur\" >Compose : Ressource Texte, Image, Couleur<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_les_etats_dans_les_elements_de_type_Composable\" >Compose : les \u00e9tats dans les \u00e9l\u00e9ments de type Composable<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-21\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#AndroidKotlin_ecriture_fichier\" >Android\/Kotlin : \u00e9criture fichier<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-22\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Premier_cas_simple_ecriture_fichier_dans_le_repertoire_prive_de_lapp\" >Premier cas simple (\u00e9criture fichier dans le r\u00e9pertoire priv\u00e9 de l&rsquo;app)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-23\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Deuxieme_cas_manipulant_des_listes_dobjets_GSON_ecriture_fichier_dans_le_repertoire_prive_de_lapp\" >Deuxi\u00e8me cas manipulant des listes d&rsquo;objets + GSON (\u00e9criture fichier dans le r\u00e9pertoire priv\u00e9 de l&rsquo;app)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-24\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Troisieme_cas_ecriture_fichier_dans_repertoire_externe\" >Troisi\u00e8me cas : \u00e9criture fichier dans r\u00e9pertoire externe<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-25\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Compose_Banniere_PUB\" >Compose : Banni\u00e8re PUB<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-26\" href=\"https:\/\/blogperso.union31.fr\/?p=3884\/#Voir_%E2%80%A6\" >Voir &#8230;<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Classes\"><\/span>Classes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Constructeur\"><\/span>Constructeur<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Il y a 2 types de constructeurs : les primaires et secondaires :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">class Heure_composant {\n    \/\/ mettre en pause le retour de l'heure\n    var Paused:Boolean = false\n    \/\/ Constructeur primaire\n    init {\n        println (\"Constructeur primaire : Je me lance ...\")\n    }\n    \/\/ Constructeur secondaire\n    constructor() {\n        println (\"Constructeur Secondaire : je me lance ...\")\n    }\n}<\/code><\/pre>\n\n\n\n<p>Instenciation<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    val maj_heure_composant:Heure_composant = Heure_composant();<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Heritage\"><\/span>H\u00e9ritage<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Par d\u00e9faut une classe est de type \u00ab\u00a0final\u00a0\u00bb. Pour qu&rsquo;elle soit h\u00e9ritable il faut le sp\u00e9cifier avec le mot clef \u00ab\u00a0open\u00a0\u00bb devant \u00ab\u00a0class\u00a0\u00bb<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">open class Mother{\n    var name:String = \"Mother\"\n}\nclass Daughter:Mother(){\n    var address:String = \"\"\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Singleton\"><\/span>Singleton<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Tr\u00e8s simple sous kotlin, il suffit d&rsquo;utiliser le mot clef \u00ab\u00a0objet\u00a0\u00bb en lieu et place de \u00ab\u00a0class\u00a0\u00bb :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">object mon_singleton {\n\n    var valeur = \"\"\n\n}\n\nfun main() {\n    \n    val objet1:mon_singleton = mon_singleton\n    val objet2:mon_singleton = mon_singleton\n    println(\"objet1 : $objet1\")\n    println(\"objet2 : $objet2\")\n    objet1.valeur = \"test singleton\"\n    println(\"objet1 : ${objet1.valeur}\")\n    println(\"objet2 : ${objet2.valeur}\")\n\n}<\/code><\/pre>\n\n\n\n<p>R\u00e9sultat :<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">objet1 : mon_singleton@378fd1ac\nobjet2 : mon_singleton@378fd1ac\nobjet1 : test singleton\nobjet2 : test singleton<\/pre>\n\n\n\n<p>Pas de constructeur mais utilisation de init possible en utilisant &lsquo;object&rsquo;<\/p>\n\n\n\n<p>Si constructeur, code plus verbeux, exemple :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">class MySingleton private constructor(private val param: String) {\n\n    companion object {\n        @Volatile\n        private var INSTANCE: MySingleton? = null\n\n        @Synchronized\n        fun getInstance(param: String): MySingleton = INSTANCE ?: MySingleton(param).also { INSTANCE = it }\n    }\n\n    fun printParam() {\n        print(\"Param: $param\")    \n    }\n}<\/code><\/pre>\n\n\n\n<p>utilisation :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">MySingleton.getInstance(\"something\").printParam()<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Fonctions\"><\/span>Fonctions<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>R\u00e9capitulatif sur la d\u00e9claration des fonctions, les param\u00e8tres, etc.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Declaration\"><\/span>D\u00e9claration<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Simple fonction sans retour de param\u00e8tres et prenant une valeur en param\u00e8tre<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun ma_fonction(valeur1:String) {\n    println (\"valeur1 : $valeur1\")\n}\n\nma_fonction(\"test\")<\/code><\/pre>\n\n\n\n<p>Simple fonction avec valeur par defaut pour un param\u00e8tre :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun ma_fonction(valeur1:String=\"\") {\n    <em>println <\/em>(\"valeur1 : $valeur1\")\n}\nma_fonction()<\/code><\/pre>\n\n\n\n<p>Principe des param\u00e8tres nomm\u00e9s quand la fonction est appel\u00e9es :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun ma_fonction(valeur1:String=\"\", valeur2:String=\"\") {\n    println (\"valeur1 : $valeur1\")\n    println (\"valeur2 : $valeur2\")\n}\n\nma_fonction(\"val1\",\"val2\")     \/\/ utilisation initiale comme en JAVA\nma_fonction()                  \/\/ comme les param\u00e8tres ont une valeur par d\u00e9faut --&gt; pas besoin de sp\u00e9cifier une valeur\nma_fonction(valeur2 = \"val2\")  \/\/ utilisation via \"param\u00e8tre nomm\u00e9\"<\/code><\/pre>\n\n\n\n<p>Fonction avec retour :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun ma_fonction(valeur1:String=\"\", valeur2:String=\"\"): String {\n    \/\/ ...\n    return \"$valeur1 --&gt; $valeur2\"\n}\n\nval val_finale:String = ma_fonction()\nval val_finale2:String = ma_fonction(valeur1 = \"val1\", valeur2 = \"val2\")<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Fonction en param\u00e8tre<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun ma_fonction(callback:()-&gt;Unit) {\n        println (\"calculs ...\")\n        callback()\n        println(\"fin\")\n}\n\n    \/\/ Utilisation\n    ma_fonction(callback = {\n        println (\" int\u00e9rieur callback\")\n    })\n\n    \/\/ raccourci (possible car un seul param\u00e8tre attendant une fonction)\n    ma_fonction { println(\"int\u00e9rieur callback\") }<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Fonction prenant une fonction en param\u00e8tre de mani\u00e8re optionnelle + surchage de fonction :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\/\/ fonction avec callback fonctionnel\nfun ma_fonction( callbacks: (()-&gt;Unit)? = null  ): String {\n    \/\/ ...\n    return \"\"\n}\n\/\/ fonction surcharge\nfun ma_fonction (valeur1:String):String {\n    \/\/ ...\n    return \"\"\n}\n\n\/\/ Utilisation de la fonction de diff\u00e9rentes mani\u00e8res\nma_fonction {\n    println (\"callback ...\")\n}\nma_fonction()\nma_fonction(valeur1 = \"test\")<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Lancer_une_activite_et_passage_de_parametres\"><\/span>Lancer une activit\u00e9 et passage de param\u00e8tres<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Sur premi\u00e8re activit\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\/\/ Fetching the Local Context\nval mContext = LocalContext.current\n\n\/\/ d\u00e9claration intent\nval intent = Intent(mContext,MainActivity2::class.java)\n\/\/ ajout param\u00e8tre\nintent.putExtra(\"valeur1\",\"Valeur de passage\")\n\/\/ Lance l'activit\u00e9\nmContext.startActivity(intent)\n<\/code><\/pre>\n\n\n\n<p>Sur deuxi\u00e8me activit\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\/\/ r\u00e9cup\u00e9ration du contexte\nval context = LocalContext.current\n\/\/ r\u00e9cup\u00e9ration de l'intent de l'appli en cours\nval intent = (context as MainActivity2).intent\n\/\/ r\u00e9cup\u00e9ration de la donn\u00e9e\nval valeur:String? = intent.getStringExtra(\"valeur1\")<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Log\"><\/span>Log<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Utilisation de la classe utilitaire LOG pour \u00e9viter les println() &#8230;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun code_click() {\n\n    Log.i(\"code_click\",\"d\u00e9but code\")\n\n    Log.d(\"code_click\",\"debug 1\")\n    Log.d(\"code_click\",\"debug 2\")\n\n    Log.w(\"code_click\",\"proche manque ressource\")\n\n    Log.e(\"code_click\",\"Erreur ...\")\n\n    Log.i(\"code_click\",\"fin code\")\n\n}\n\n@Composable\nfun App_main13() {\n\n    Surface() {\n        Column() {\n            Row() {\n                Text(text = \"Titre\")\n            }\n            Row() {\n                Button(onClick = {\n                    Log.i(TAG,\"Click bouton\")\n                    Log.i(\"MonTAG\",\"Click bouton\")\n                    code_click()\n                }) {\n                    Text(text = \"Cliquer moi pour log\")\n                }\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>R\u00e9sultat :<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">2022-06-27 16:25:05.915 17056-17069\/com.example.test_compose7_navigation W\/System: A resource failed to call close. \n2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation I\/ContentValues: Click bouton\n2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation I\/MonTAG: Click bouton\n2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation I\/code_click: d\u00e9but code\n2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation D\/code_click: debug 1\n2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation D\/code_click: debug 2\n2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation W\/code_click: proche manque ressource\n<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation E\/code_click: Erreur ...<\/mark>\n2022-06-27 16:25:25.894 17056-17056\/com.example.test_compose7_navigation I\/code_click: fin code<\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Liens :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>page officielle : <a rel=\"noreferrer noopener\" href=\"https:\/\/developer.android.com\/reference\/kotlin\/android\/util\/Log\" target=\"_blank\">https:\/\/developer.android.com\/reference\/kotlin\/android\/util\/Log<\/a><\/li>\n\n\n\n<li>d\u00e9sactiver certains log en version release : <a rel=\"noreferrer noopener\" href=\"https:\/\/thanhtungvo.medium.com\/disable-debug-log-on-release-android-6a7f3ab86126\" target=\"_blank\">https:\/\/thanhtungvo.medium.com\/disable-debug-log-on-release-android-6a7f3ab86126<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Thread_coroutine_channel_et_autre\"><\/span>Thread, coroutine, channel et autre<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Ressources :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>lien : <a rel=\"noreferrer noopener\" href=\"https:\/\/kotlinlang.org\/docs\/coroutines-guide.html\" target=\"_blank\">https:\/\/kotlinlang.org\/docs\/coroutines-guide.html<\/a><\/li>\n\n\n\n<li>lien : <a rel=\"noreferrer noopener\" href=\"https:\/\/www.baeldung.com\/kotlin\/threads-coroutines\" target=\"_blank\">https:\/\/www.baeldung.com\/kotlin\/threads-coroutines<\/a><\/li>\n\n\n\n<li>lien : <a rel=\"noreferrer noopener\" href=\"https:\/\/borntocode.fr\/android-introduction-aux-coroutines-de-kotlin\/\" target=\"_blank\">https:\/\/borntocode.fr\/android-introduction-aux-coroutines-de-kotlin\/<\/a><\/li>\n\n\n\n<li>lien : <a href=\"https:\/\/www.baeldung.com\/kotlin\/channels\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.baeldung.com\/kotlin\/channels<\/a><\/li>\n\n\n\n<li><\/li>\n<\/ul>\n\n\n\n<p>Le principe des Threads est toujours pr\u00e9sent comme dans Java<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">    val mon_thread = Thread{\n        println(\"Hello\")\n        Thread.sleep(5000)\n        println(\"World\")\n    }\n    mon_thread.start()<\/code><\/pre>\n\n\n\n<p>Une autre impl\u00e9mentation sous Kotlin est possible :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">    val mon_thread2 = thread(start = true) {\n        println(\"Hello2\")\n        Thread.sleep(5000)\n        println(\"World2\")\n    }<\/code><\/pre>\n\n\n\n<p>Le thread va s&rsquo;executer directement. Bien que cette \u00e9criture soit concise, dans l&rsquo;EDI Android, la variable \u00ab\u00a0mon_thread2\u00a0\u00bb est marqu\u00e9e comme non utilis\u00e9e alors que si en fait &#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"814\" height=\"176\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-13.png\" alt=\"\" class=\"wp-image-3963\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-13.png 814w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-13-300x65.png 300w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-13-768x166.png 768w\" sizes=\"auto, (max-width: 814px) 100vw, 814px\" \/><\/figure>\n\n\n\n<p>Mais il existe en plus de principe de coroutines, pr\u00e9conis\u00e9 par KOTLIN, plus s\u00fbr et demandant moins de ressouces m\u00e9moire  :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    runBlocking {\n        val job = launch{\n            println(\"${Thread.currentThread()} has run.\")\n            delay(5000)\n            println(\"Hello world\")\n        }\n    }<\/code><\/pre>\n\n\n\n<p>Dans cet exemple, le code appelant sera en attente que les lignes ci-dessus soit enti\u00e8rement execut\u00e9es &#8230; ce qui ne correspondant pas \u00e0 l&rsquo;effet du code avec les Threads.<\/p>\n\n\n\n<p>Il faut donc passer via Async :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    val tache = GlobalScope.async {\n        println(\"Hello3\")\n        delay(5000)\n        println(\"World3\")\n    }\n\n    runBlocking {\n        val job = launch {\n            tache\n        }\n    }<\/code><\/pre>\n\n\n\n<p>et pour faire en sorte que le processus parent attende :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    val tache = GlobalScope.async () {\n        println(\"Hello3\")\n        delay(5000)\n        println(\"World3\")\n        return@async \"traitement fini\"\n    }\n\n    runBlocking {\n        val res = tache<strong>.await()<\/strong>\n        println(\"resultat : ${res}\")\n    }<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Exemple plus complet alliant coroutine, channel et mise \u00e0 jour de composant graphique :<\/p>\n\n\n\n<p>Un channel permet de discuter entre coroutine. C&rsquo;est par ce proc\u00e9d\u00e9 que la mise \u00e0 jour de l&rsquo;heure est \u00ab\u00a0mise en pause\u00a0\u00bb au sein de la coroutine \u00ab\u00a0MAJ_heure\u00a0\u00bb (pas le job qui tourne tout le temps, mais juste la transmission de l&rsquo;information de l&rsquo;heure au sein avant appel du callback)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\n\/\/ Permet de communiquer entre job\nval channel = Channel&lt;String&gt;()\n\n\/\/ Fonction qui va envoyer l'heure via callable\nsuspend fun MAJ_heure(callbacks_heure: ((heure:String) -&gt; Unit)?)  {\n\n    var paused:Boolean = false\n\n    \/\/ boucle sans fin (pas bien :) )\n    while (true) {\n\n        \/\/ channel pas vide ?\n        if (!channel.isEmpty) {\n            val va_tmp = channel.receive()\n            \/\/ logique de pause\n            if (va_tmp==\"pause_paspause\") { paused = !paused}\n            if (va_tmp==\"1\") { paused = true}\n            if (va_tmp==\"0\") { paused = false}\n        }\n        \/\/ un petit d\u00e9lai de pause\n        delay(50)\n\n        \/\/ heure en string\n        val cal = if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.N) {\n            Calendar.getInstance()\n        } else {\n            TODO(\"VERSION.SDK_INT &lt; N\")\n        }\n        val heure = cal.get(Calendar.HOUR_OF_DAY)\n        val minute = cal.get(Calendar.MINUTE)\n        val seconde = cal.get(Calendar.SECOND)\n        val milliseconde = cal.get(Calendar.MILLISECOND)\n\n        \/\/ si callback d\u00e9fini\n        if (callbacks_heure != null) {\n            \/\/ pas en pause\n            if (paused==false) {\n                \/\/ envoi heure au callback\n                callbacks_heure(\"$heure : $minute : $seconde : $milliseconde\")\n            }\n        }\n    }\n}\n\n\n\n@SuppressLint(\"CoroutineCreationDuringComposition\")\n@Composable\nfun App_main10() {\n\n    var heure:String by remember { mutableStateOf(\"12:00:00\")}\n\n    \/\/ lance actualisation variable heure\n    val job = GlobalScope.launch {\n        var maj_heure2 = MAJ_heure {\n            try{\n                heure=it\n            } catch (e:Exception) {\n            }\n        }\n    }\n\n    \/\/ Affichage global\n    Surface() {\n        Column(modifier = Modifier.fillMaxWidth().padding(10.dp)) {\n            Row{\n                Text (\"Bienvenue sur l'appli qui tue \\nElle va vous donner l'heure ...\")\n            }\n\n            Spacer(modifier = Modifier.height(10.dp))\n            Row() {\n                Text (\" --&gt; Heure :  $heure \")\n            }\n\n            Spacer(modifier = Modifier.height(10.dp))\n            Row() {\n                Button(\n                    onClick = {\n                        GlobalScope.launch {\n                            channel.send(\"pause_paspause\")\n                        }\n                    }) {\n                    Text(\"Pause \/ pas pause Affichage\")\n                }\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"339\" height=\"148\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-14.png\" alt=\"\" class=\"wp-image-3987\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-14.png 339w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-14-300x131.png 300w\" sizes=\"auto, (max-width: 339px) 100vw, 339px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Autre solution plus simple et sans passer par un channel pour mettre en pause l&rsquo;affichage de l&rsquo;heure :<\/p>\n\n\n\n<p>Cr\u00e9ation d&rsquo;une classe d\u00e9di\u00e9e :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">package com.example.test_compose7_navigation.Classes\nimport android.icu.util.Calendar\nimport android.os.Build\nimport kotlinx.coroutines.GlobalScope\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\n\nclass Heure_composant ( var callbacks_heure:(heure:String)-&gt;Unit={}) {\n\n    var Paused:Boolean = false   \/\/ pour mettre en pause le retour de l'heure\n\n    init {\n        Demmarer()\n    }\n\n    \/\/ lance job qui donner l'heure via le callback\n    fun Demmarer() {\n\n        val job = GlobalScope.launch {\n            \/\/ boucle sans fin (pas bien :) )\n            while (true) {\n                \/\/ un petit d\u00e9lai de pause\n                delay(50)\n                \/\/ heure en string\n                val cal = if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.N) {\n                    Calendar.getInstance()\n                } else {\n                    TODO(\"VERSION.SDK_INT &lt; N\")\n                }\n                val heure = cal.get(Calendar.HOUR_OF_DAY)\n                val minute = cal.get(Calendar.MINUTE)\n                val seconde = cal.get(Calendar.SECOND)\n                val milliseconde = cal.get(Calendar.MILLISECOND)\n\n                \/\/ Affichage en oause ?\n                if (!Paused) {\n                    \/\/ envoi heure au callback\n                    callbacks_heure(\"$heure : $minute : $seconde : $milliseconde\")\n                }\n            }\n        }\n    }\n\n    fun Pause_pas_pause() {\n        Paused=!Paused\n    }\n\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Utilisation de la classe dans le \u00ab\u00a0composable\u00a0\u00bb<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">@Composable\nfun App_main10() {\n\n    var heure:String by remember { mutableStateOf(\"12:00:00\")}\n\n    \/\/ lance actualisation variable heure\n    val maj_heure_composant:Heure_composant = Heure_composant() {\n        try {\n            heure=it\n        } catch (e:Exception) {\n        }\n    }\n\n    \/\/ Affichage global\n    Surface() {\n        Column(modifier = Modifier.fillMaxWidth().padding(10.dp)) {\n            Row{\n                Text (\"Bienvenue sur l'appli qui tue \\nElle va vous donner l'heure ...\")\n            }\n\n            Spacer(modifier = Modifier.height(10.dp))\n            Row() {\n                Text (\" --&gt; Heure :  $heure \")\n            }\n\n            Spacer(modifier = Modifier.height(10.dp))\n            Row() {\n                Button(\n                    onClick = {\n                        maj_heure_composant.Pause_pas_pause()\n                    }) {\n                    Text(\"Pause \/ pas pause Affichage\")\n                }\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_recuperer_le_contexte_de_lapplication\"><\/span>Compose : r\u00e9cup\u00e9rer le contexte de l&rsquo;application<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">val context = LocalContext.current<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_mise_en_forme_generale\"><\/span>Compose : mise en forme g\u00e9n\u00e9rale<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Utiliser les composables<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Column<\/li>\n\n\n\n<li>Row<\/li>\n\n\n\n<li>Spacer <\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\n    Column(\n        modifier = Modifier\n            .border(width = 2.dp, color = Color(0xFF0000FF))\n            .padding(5.dp)\n    ) {\n\n\n        Row( modifier = Modifier\n            .border(width = 1.dp, color = Color(0xFF00FF00))\n            .padding(2.dp)) {\n            Text(text = \"AAA\", modifier = Modifier.border(width = 1.dp, color = Color(0xFFD1AA4F)))\n            Text(text = \"BBB\")\n        }\n\n        Row(modifier = Modifier\n            .border(width = 1.dp, color = Color(0xFF00FF00))\n            .padding(2.dp)) {\n            Text(text = \"CCC\")\n            Text(text = \"DDD\")\n            Column(modifier = Modifier\n                .border(width = 1.dp, color = Color(0xFF0000FF))\n                .padding(2.dp)) {\n                Text(text = \"EEEE\")\n                Spacer(modifier = Modifier.height(5.dp).background(Color(0xFF676767)))\n                Text(text = \"FFFF\")\n            }\n        }\n        Row (modifier = Modifier\n            .border(width = 1.dp, color = Color(0xFF00FF00))\n            .padding(2.dp)){\n            Text(text = \"GGG\")\n        }\n\n    }<\/code><\/pre>\n\n\n\n<p>Ce qui donne<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"144\" height=\"140\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-4.png\" alt=\"\" class=\"wp-image-3923\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_LazyColumn_ou_LazyRow_et_Item_Divider\"><\/span>Compose : LazyColumn ou LazyRow (et Item, Divider)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u00c9quivalent du recylcerView<\/p>\n\n\n\n<p>Ressources :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.android.com\/jetpack\/compose\/lists\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/developer.android.com\/jetpack\/compose\/lists<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\n    var liste_texte = mutableListOf&lt;String&gt;(\"\")\n    for (i in 1..1000) {\n        liste_texte.add(\"texte n\u00b0$i\")\n    }\n\n    Surface() {\n        LazyColumn() {\n            for ((index,value) in liste_texte.withIndex()) {\n                if ( index % 9 == 1 ) {\n                    item {\n                        Spacer(modifier = Modifier\n                            .background(Color(0x467C9261))\n                            .fillMaxWidth()\n                            .height(10.dp)\n                            )\n                        Divider()\n                    }\n                }\n                item {\n                    Text(text = value)\n                    Divider()\n                }\n            }\n        }\n    }<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"232\" height=\"292\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-5.png\" alt=\"\" class=\"wp-image-3929\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_Card\"><\/span>Compose : Card<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>R\u00e9f\u00e9rence :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.jetpackcompose.net\/jetpack-compose-card\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.jetpackcompose.net\/jetpack-compose-card<\/a><\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    Surface( modifier = Modifier.fillMaxWidth()) {\n        Column( modifier = Modifier.padding(10.dp)) {\n             Card(elevation = 10.dp, modifier = Modifier.padding(4.dp)) {\n                 Row( verticalAlignment = Alignment.CenterVertically) {\n                     Icon(imageVector = Icons.Default.Info, contentDescription = \"\", modifier = Modifier.padding(4.dp))\n                     Text (\"Mon Card\", modifier = Modifier.padding(8.dp))\n                 }\n             }\n        }\n    }<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"376\" height=\"156\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-6.png\" alt=\"\" class=\"wp-image-3933\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-6.png 376w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-6-300x124.png 300w\" sizes=\"auto, (max-width: 376px) 100vw, 376px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_SnackBarHost_equivalent_a_Toast\"><\/span>Compose : SnackBarHost (\u00e9quivalent \u00e0 Toast)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Cas n\u00b01 (sans personnalisation de la bulle)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    val scope = rememberCoroutineScope()\n    var snackbarHostState by remember {mutableStateOf(SnackbarHostState())}\n\n    Surface() {\n        Column(modifier = Modifier\n            .fillMaxWidth()\n            .padding(10.dp)) {\n\n                Button(onClick = { \/*TODO*\/\n                    scope.launch {\n                        snackbarHostState.showSnackbar(\"Message vers utilisateur\")\n                        }\n                    }\n            )   {\n                Text(text = \"Cliquer moi pour un snack ...\")\n                }\n        }\n        SnackbarHost(hostState = snackbarHostState)\n    }<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"342\" height=\"102\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-8.png\" alt=\"\" class=\"wp-image-3944\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-8.png 342w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-8-300x89.png 300w\" sizes=\"auto, (max-width: 342px) 100vw, 342px\" \/><\/figure>\n\n\n\n<p>Cas n\u00b02 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    val scope = rememberCoroutineScope()\n    var snackbarHostState by remember {mutableStateOf(SnackbarHostState())}\n\n    Surface() {\n        Column(modifier = Modifier\n            .padding(10.dp))\n        {\n            Button(onClick = {\n                \/\/ on lance le snackbar\n                scope.launch {\n                    snackbarHostState.showSnackbar(\"\", duration = SnackbarDuration.Short)\n                }\n            })   {\n                Text(text = \"Cliquer moi pour un snack ...\")\n            }\n        }\n    }\n\n    SnackbarHost(\n        hostState = snackbarHostState) {\n        Box(\n            contentAlignment = Alignment.Center,\n            modifier = Modifier.fillMaxSize()\n        ) {\n            Card(\n                shape = RoundedCornerShape(8.dp),\n                border = BorderStroke(2.dp, Color.White),\n                modifier = Modifier.padding(10.dp),\n                elevation = 10.dp\n            ) {\n                Row(\n                    modifier = Modifier.padding(8.dp),\n                    verticalAlignment = Alignment.CenterVertically\n                ) {\n                    Text(text = \"Message bulle pour utilisateur\")\n                    Spacer(modifier = Modifier.width(10.dp))\n                    Button(onClick =\n                    {  \/\/ on force l'arret du snackBar ...\n                        snackbarHostState.currentSnackbarData?.dismiss()\n                    }) {\n                        Text (\"OK !\")\n                    }\n                }\n            }\n        }\n    }<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"328\" height=\"303\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-7.png\" alt=\"\" class=\"wp-image-3942\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-7.png 328w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-7-300x277.png 300w\" sizes=\"auto, (max-width: 328px) 100vw, 328px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_EditText\"><\/span>Compose : EditText<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Ressources :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.goodrequest.com\/blog\/jetpack-compose-basics-text-input\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.goodrequest.com\/blog\/jetpack-compose-basics-text-input<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/material.io\/components\/text-fields\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/material.io\/components\/text-fields<\/a><\/li>\n\n\n\n<li><\/li>\n<\/ul>\n\n\n\n<p>Les champs d&rsquo;\u00e9dition sont :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>TextField<\/li>\n\n\n\n<li>OutlinedTextField<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>Exemple :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    var text by remember { mutableStateOf(\"\")}\n    var is_error by remember {mutableStateOf(false)}\n    var image_vector_error by remember { mutableStateOf(Icons.Default.Check)}\n\n    OutlinedTextField(\n        value = text,\n        \/\/ permet d'\u00e9diter ...\n        onValueChange = {\n            \/\/ MAJ texte\n            text = it\n            \/\/ D\u00e9tecte une erreur ...\n            is_error = if (text.equals(\"erreur\")) true else false\n            if (is_error) {\n                image_vector_error = Icons.Default.Warning\n            } else {\n                image_vector_error = Icons.Default.Check\n            }\n        },\n        \/\/ Titre du champ\n        label = {Text(\"Nom\")},\n        isError = is_error,\n        modifier = Modifier.padding( top =10.dp, start = 10.dp, bottom = 4.dp),\n        \/\/ Texte compl\u00e9menataire si pas de texte saii\n        placeholder = {\n          Text(text = \"Saisir votre nom ...\")  \n        },\n        \/\/ Composant avant Texte (Image, texte, autres...)\n        leadingIcon = { Icon(imageVector = Icons.Default.Info, contentDescription = \"\")   },\n        \/\/ Composant apr\u00e8s texte (Image, texte, autres...)\n        trailingIcon = { Icon(imageVector = image_vector_error, contentDescription = \"\") },\n\n    )\n    \/\/ si erreur --&gt; affiche texte explication en dessous du TextField\n    if (is_error) {\n        Text(\n            text = \"Erreur dans la saisie ...\",\n            color = MaterialTheme.colors.error,\n            style = MaterialTheme.typography.caption,\n            modifier = Modifier.padding(start = 20.dp)\n        )\n    }\n<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"386\" height=\"92\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-2.png\" alt=\"\" class=\"wp-image-3916\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-2.png 386w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-2-300x72.png 300w\" sizes=\"auto, (max-width: 386px) 100vw, 386px\" \/><figcaption class=\"wp-element-caption\">Affichage initial<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"385\" height=\"93\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-3.png\" alt=\"\" class=\"wp-image-3918\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-3.png 385w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-3-300x72.png 300w\" sizes=\"auto, (max-width: 385px) 100vw, 385px\" \/><figcaption class=\"wp-element-caption\">Une fois entr\u00e9 dans le composant<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"380\" height=\"93\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-1.png\" alt=\"\" class=\"wp-image-3914\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-1.png 380w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-1-300x73.png 300w\" sizes=\"auto, (max-width: 380px) 100vw, 380px\" \/><figcaption class=\"wp-element-caption\">Apr\u00e8s premi\u00e8re saisie<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"385\" height=\"117\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image.png\" alt=\"\" class=\"wp-image-3912\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image.png 385w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-300x91.png 300w\" sizes=\"auto, (max-width: 385px) 100vw, 385px\" \/><figcaption class=\"wp-element-caption\">Affichage quand une erreur &#8230;<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_bouton_Button_OutlinedButton_TextButton\"><\/span>Compose : bouton (Button, OutlinedButton, TextButton)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>3 types de bouton d&rsquo;apr\u00e8s material (v2)<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">        Column(modifier = Modifier.padding(10.dp)) {\n\n            Row() {\n                Button(onClick = { \/*TODO*\/ }) {\n                    Text(\"Boutton\")\n                }\n                Spacer (modifier= Modifier.width(10.dp) )\n                Button(onClick = { \/*TODO*\/ }) {\n                    Text(\"Boutton\")\n                    Icon(imageVector = Icons.Default.Close, contentDescription = \"\",\n                    modifier = Modifier.padding(start = 4.dp))\n                }\n            }\n            \n            OutlinedButton(onClick = { \/*TODO*\/ }) {\n                Text(\"Outlined Boutton\")\n            }\n\n            TextButton(onClick = { \/*TODO*\/ }) {\n                Text(\"Texte Boutton\")\n            }\n        }<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"214\" height=\"138\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-10.png\" alt=\"\" class=\"wp-image-3948\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_TopAppBar\"><\/span>Compose : TopAppBar<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>2 impl\u00e9mentation possibles.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Exemple avec une<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">        Scaffold(\n            topBar = {\n<mark style=\"background-color:#7bdcb5\" class=\"has-inline-color\">                TopAppBar(\n                    title = {\n                        Text(\"Discute avec ta banque\")\n                    },\n                    navigationIcon = {\n                        IconButton(onClick = { \/*TODO*\/ }) {\n                            Icon(Icons.Default.ArrowBack,\"\")\n                        }\n                    },\n                    actions = {\n                        IconButton(onClick = { \/*TODO*\/ }) {\n                            Icon(Icons.Default.Search,\"\")\n                        }\n                        IconButton(onClick = { \/*TODO*\/ }) {\n                            Icon(Icons.Default.List,\"\")\n                        }\n                    }\n                )<\/mark>\n            }\n        ) {\n\n           Column {\n               LazyColumn() {\n                   for (i in 1..40) {\n                       item {\n                           Text (\"Contenu appli $i.\")\n                       }\n                   }\n               }\n           }\n\n        }<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"359\" height=\"236\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-11.png\" alt=\"\" class=\"wp-image-3956\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-11.png 359w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-11-300x197.png 300w\" sizes=\"auto, (max-width: 359px) 100vw, 359px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_AlertDialog\"><\/span>Compose : AlertDialog<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>2 impl\u00e9mentations &#8230;<\/p>\n\n\n\n<p>code avec une :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">      var afficher_dialogue by remember {mutableStateOf(false)}\n  \n      Column() {\n\n            Button(onClick = {\n                afficher_dialogue = true\n            }) {\n                Text(\"AlertDIalog\")\n            }\n\n            if (afficher_dialogue) {\n                \n                AlertDialog(\n                    onDismissRequest =\n                    { \/\/Quand on clique en dehors de la boite de dialogue\n                      \/\/ Permet de g\u00e9rer le modal ou pas ...\n                        afficher_dialogue = false\n                    },\n                    title = {\n                            Text(text = \"Bienvenue\")\n                    },\n                    text = {\n                           Text(\"Bienvenue sur la nouvelle boite dialogue\")\n                    },\n                   confirmButton = {\n                       Button(onClick = { afficher_dialogue = false },) {\n                           Text(\"OK\")\n                       }\n                   },\n                    dismissButton = {\n                        OutlinedButton(onClick = { \/*TODO*\/ },) {\n                            Text(\"Annuler\")\n                        }\n                    }\n                )\n            }\n        }<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"359\" height=\"377\" src=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-12.png\" alt=\"\" class=\"wp-image-3958\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-12.png 359w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-12-286x300.png 286w\" sizes=\"auto, (max-width: 359px) 100vw, 359px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_Ressource_Texte_Image_Couleur\"><\/span>Compose : Ressource Texte, Image, Couleur<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">@Composable\nfun App_main12() {\n\n    Surface() {\n        Column() {\n            Row() {\n                val ressources = LocalContext.current.resources\n\n                Image(\n                    painter = painterResource(id = R.drawable.img),\n                    contentDescription = null,\n                    modifier = Modifier.width(30.dp).padding(2.dp)\n                    )\n                \n                if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.M) {\n                    Text(\n                        text =  ressources.getString(R.string.titre),\n                        color = Color(ressources.getColor(R.color.couleur_titre,null))\n                    )\n                } else {\n                    Text(\n                        text =  ressources.getString(R.string.titre),\n                        color = Color(ressources.getColor(R.color.couleur_titre))\n                    )\n                }\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Liens :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>pr\u00e9sentation ANDROID : <a href=\"https:\/\/developer.android.com\/jetpack\/compose\/resources\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/developer.android.com\/jetpack\/compose\/resources<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_les_etats_dans_les_elements_de_type_Composable\"><\/span>Compose : les \u00e9tats dans les \u00e9l\u00e9ments de type Composable<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>1 Faire au maximum des composants sans \u00e9tats (StateLess) :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>pour pouvoir tout re-initialiser si besoin<\/li>\n<\/ul>\n\n\n\n<p>2 Utiliser un modelView le plus possible dans l&rsquo;activit\u00e9 ce qui simplifiera grandement la gestion des composants et sous composants<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>liens utiles : <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a rel=\"noreferrer noopener\" href=\"https:\/\/www.composables.co\/blog\/state\" target=\"_blank\">https:\/\/www.composables.co\/blog\/state<\/a> \n<ul class=\"wp-block-list\">\n<li>permet de comprendre pourquoi il faut faire du StateLess<\/li>\n\n\n\n<li>explique le bug de MAJ des BasicTextField<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"AndroidKotlin_ecriture_fichier\"><\/span>Android\/Kotlin : \u00e9criture fichier <span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Premier_cas_simple_ecriture_fichier_dans_le_repertoire_prive_de_lapp\"><\/span>Premier cas simple (\u00e9criture fichier dans le r\u00e9pertoire priv\u00e9 de l&rsquo;app)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Fonctions permettant la lecture ou l&rsquo;\u00e9criture dans un fichier<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun ecrire_text(context:Context,personne:Personne, callback_texte:(texte_retour:String)-&gt;Unit={}) {\n    val fileoutputStream:FileOutputStream\n    val nom_fichier =\"test.txt\"\n    fileoutputStream =  context.openFileOutput(nom_fichier, Context.MODE_PRIVATE)\n    fileoutputStream.write(personne.toString().toByteArray())\n    callback_texte(\"Ecriture fichier effctu\u00e9e\")\n}\n\nfun lire_text(context:Context, callback_texte:(texte_retour:String)-&gt;Unit={})  {\n    var fileInputStream:FileInputStream?=null\n    val nom_fichier =\"test.txt\"\n\n    \/\/ fichier existant !\n    val file_exist = context.getFileStreamPath(nom_fichier).exists()  \/\/ va v\u00e9rifier le fichier en private\n    if (file_exist) {\n        fileInputStream = context.openFileInput(nom_fichier)\n        var inputStreamReader: InputStreamReader = InputStreamReader(fileInputStream)\n        val bufferedReader: BufferedReader = BufferedReader(inputStreamReader)\n        val stringBuilder: StringBuilder = StringBuilder()\n        var text: String? = null\n        while ({ text = bufferedReader.readLine(); text }() != null) {\n            stringBuilder.append(text)\n        }\n        callback_texte(stringBuilder.toString())\n    } else {\n        callback_texte(\"Fichier inexistant\")\n    }\n}\n\n<\/code><\/pre>\n\n\n\n<p>Code compose associ\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\n@Composable\nfun App_main11() {\n\n    var texte_resultat by remember{ mutableStateOf(\"\")}\n    val context = LocalContext.current\n    val personne1 = Personne(\n        Id=1,\n        Nom = \"lulu\",\n        Premon = \"lolo\",\n        Age = 19\n    )\n    Surface {\n        Column(modifier = Modifier.padding(10.dp)) {\n            Row() {\n                Text(text = \"Test Ecriture\/Lecture Fichier\")\n            }\n            Spacer(modifier = Modifier.height(10.dp))\n            Row() {\n                Button(onClick = {\n                    \/\/Ecroture fichier\n                    ecrire_text(context,personne1) {\n                        texte_resultat = it\n                    }\n                }) {\n                    Text(text = \"Ecrire\")\n                }\n            }\n            Spacer(modifier = Modifier.height(10.dp))\n            Row() {\n                Button(onClick = {\n                    \/\/lecture fichier\n                    lire_text(context) {\n                        texte_resultat=it\n                    }\n                }) {\n                    Text(text = \"lire\")\n                }\n            }\n            Spacer(modifier = Modifier.height(10.dp))\n\n            Row() {\n                Text(text = texte_resultat)\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"312\" height=\"164\" src=\"http:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-15.png\" alt=\"\" class=\"wp-image-4005\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-15.png 312w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-15-300x158.png 300w\" sizes=\"auto, (max-width: 312px) 100vw, 312px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Deuxieme_cas_manipulant_des_listes_dobjets_GSON_ecriture_fichier_dans_le_repertoire_prive_de_lapp\"><\/span>Deuxi\u00e8me cas manipulant des listes d&rsquo;objets + GSON (\u00e9criture fichier dans le r\u00e9pertoire priv\u00e9 de l&rsquo;app)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun ecrire_text(context:Context,personne:Personne, callback_texte:(texte_retour:String)-&gt;Unit={}) {\n    val fileoutputStream:FileOutputStream\n    val nom_fichier =\"test.txt\"\n\n    \/\/ Liste d'objet de type personne\n    var liste_personne:MutableList&lt;Personne&gt; = mutableListOf()\n    liste_personne.add(personne)\n    liste_personne.add(personne)\n    liste_personne.add(personne)\n\n    \/\/ liste d'objets en texte JSON\n    val json_string = Gson().toJson(liste_personne)\n\n    \/\/ enregistrement fichier (partie priv\u00e9e de l'appli)\n    fileoutputStream =  context.openFileOutput(nom_fichier, Context.MODE_PRIVATE)\n    fileoutputStream.write(json_string.toByteArray())\n    callback_texte(\"Ecriture fichier effctu\u00e9e\\n $json_string\")\n    fileoutputStream.close()\n}\n\nfun lire_text(context:Context, callback_texte:(texte_retour:String)-&gt;Unit={})  {\n    var fileInputStream:FileInputStream?=null\n    val nom_fichier =\"test.txt\"\n    val file_exist = context.getFileStreamPath(nom_fichier).exists()\n    \/\/ fichier existant ?\n    if (file_exist) {\n        \/\/ R\u00e9cup\u00e9ration contenu fichier\n        fileInputStream = context.openFileInput(nom_fichier)\n        var inputStreamReader: InputStreamReader = InputStreamReader(fileInputStream)\n        val bufferedReader: BufferedReader = BufferedReader(inputStreamReader)\n        val stringBuilder: StringBuilder = StringBuilder()\n        var text: String? = null\n        while ({ text = bufferedReader.readLine(); text }() != null) {\n            stringBuilder.append(text)\n        }\n        callback_texte(stringBuilder.toString())\n\n        \/\/ passage de texte JSON en liste de personnes\n        val json_str:String = stringBuilder.toString()\n        val stype = object : TypeToken&lt;List&lt;Personne&gt;&gt; () {}.type\n        val liste_personne:List&lt;Personne&gt; = Gson().fromJson&lt;List&lt;Personne&gt;&gt;(json_str,stype)\n        println(json_str)\n        \/\/ Affichage liste\n        for (une_personne in liste_personne) {\n            println (\"--&gt; $une_personne\")\n        }\n    } else {\n        callback_texte(\"Fichier inexistant\")\n    }\n}<\/code><\/pre>\n\n\n\n<p>Ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"323\" height=\"197\" src=\"http:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-16.png\" alt=\"\" class=\"wp-image-4013\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-16.png 323w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-16-300x183.png 300w\" sizes=\"auto, (max-width: 323px) 100vw, 323px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Troisieme_cas_ecriture_fichier_dans_repertoire_externe\"><\/span>Troisi\u00e8me cas : \u00e9criture fichier dans r\u00e9pertoire externe<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>En Java, pour \u00e9crire sur un r\u00e9pertoire \u00ab\u00a0public\u00a0\u00bb comme \u00ab\u00a0Mes documents\u00a0\u00bb ou \u00ab\u00a0Download\u00a0\u00bb il \u00e9tait possible de le faire via \u00ab\u00a0context.getExternalStoragePublicDirectory\u00a0\u00bb.<\/p>\n\n\n\n<p>Or en kotlin, cette fonction n&rsquo;est pas disponible, voire depr\u00e9ci\u00e9e depuis Android Q.<\/p>\n\n\n\n<p>Nous allons voir comment cr\u00e9er un fichier et y ins\u00e9rer du contenu avant toute chose :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    val nom_fichier = \"fichier_externe.txt\"\n\n    val path = context.getFilesDir().getAbsolutePath()\n    val fichier = File(path, nom_fichier)\n\n    println(\"path : \" + fichier.path)\n    println(\"absoluteFile  : \" + fichier.absoluteFile)\n    println(\"absolutePath  : \" + fichier.absolutePath)\n    println(\"canonicalFile : \" + fichier.canonicalFile)\n    println(\"canonicalPath : \" + fichier.canonicalPath)\n\n    println(\"\")\n\n    \/\/ cr\u00e9ation du fichier\n    val isNewFileCreated :Boolean = fichier.createNewFile()\n    println (\" isNewFileCreated : $isNewFileCreated\")\n\n    \/\/ fichier d\u00e9ja cr\u00e9e ?\n    if (!isNewFileCreated) {\n        \/\/ suppression du fichier\n        val fic_efface = fichier.delete()\n        println(\"fichier effac\u00e9 : $fic_efface\" )\n\n    }\n\n    println (\"Fichier existant : \" + fichier.exists())\n    println (\"Re cr\u00e9ation du fichier : \" + fichier.createNewFile())\n    println (\"Possibilit\u00e9 d'\u00e9crire dans le fichier : \" + fichier.canWrite())\n\n    \/\/ Ecriture via \"PrintWriter\"\n    println (\" \")\n    println (\"Ecriture via printWriter\")\n    println (\"taille fichier : \" + fichier.length())\n    fichier.printWriter().use {\n        out-&gt; out.println(\"test\")\n    }\n    \n    println (\"taille fichier : \" + fichier.length())\n    println (\"Re cr\u00e9ation du fichier : \" + fichier.createNewFile())\n\n    \/\/ Ecriture via \"writeText\n    println (\" \")\n    println (\"Ecriture via writeText\")\n    println (\"taille fichier : \" + fichier.length())\n    fichier.writeText(\"ma ligne de texte\")\n    println (\"taille fichier : \" + fichier.length())\n    fichier.writeText(\"ma ligne de texte\")\n    println (\"taille fichier : \" + fichier.length())\n\n    \/\/ Ecriture via \"Files.write\"\n    println (\" \")\n    println (\"Ecriture via Files.write \")\n\n    val contenu = \" Du texte \u00e0 GOGO de GOGO...\"\n    if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {\n        Files.write(fichier.toPath(),contenu.toByteArray(), StandardOpenOption.WRITE)\n    }\n    println (\"taille fichier : \" + fichier.length())<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Autre exemple plus court sauvegardant une liste d&rsquo;objet en format JSON<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    \/\/ Liste d'objets de type personne\n    var liste_personne:MutableList&lt;Personne&gt; = mutableListOf()\n    liste_personne.add(personne)\n    liste_personne.add(personne)\n    liste_personne.add(personne)\n    \/\/ liste d'objets en texte JSON\n    val json_string = Gson().toJson(liste_personne)\n\n    val path = context.getFilesDir().getAbsolutePath()\n    val fichier = File(path, nom_fichier)\n\n    fichier.createNewFile()\n    fichier.writeBytes(json_string.toByteArray())\n    println (\"taille fichier : \" + fichier.length())<\/code><\/pre>\n\n\n\n<p>et le code permettant de lire le fichier cr\u00e9\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    val nom_fichier = \"fichier_externe.txt\"\n    val path = context.getFilesDir().getAbsolutePath()\n    val fichier = File(path, nom_fichier)\n\n    if (fichier.exists()) {\n        val texte_fichier = fichier.readText()\n        println(\"tmp : $texte_fichier\")\n\n        \/\/ passage de texte JSON en liste de personnes\n        val stype = object : TypeToken&lt;List&lt;Personne&gt;&gt; () {}.type\n        val liste_personne:List&lt;Personne&gt; = Gson().fromJson&lt;List&lt;Personne&gt;&gt;(texte_fichier,stype)\n\n        \/\/ Affichage liste\n        for (une_personne in liste_personne) {\n            println (\"--&gt; $une_personne\")\n        }\n\n    } else {\n        println(\"Fichier inexistant\")\n    }<\/code><\/pre>\n\n\n\n<p>Prise en compte vers un r\u00e9pertoire externe :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">    \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n    \/\/ Ecriture dans Download\n\n    val chemin_download = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)\n    println(\" chemin_download : $chemin_download \")\n\n    if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.Q) {\n        \/\/\/\/ valable API &lt;= 28 (n\u00e9cessite de d\u00e9finir les permissions de lecture dans AndroidManifest.xml)\n        val fichier2 = File(chemin_download, nom_fichier)\n        try {\n            fichier2.createNewFile()\n            fichier2.writeBytes(json_string.toByteArray())\n        } catch (e:Exception) {\n\n        }\n\n    } else {\n        \/\/\/\/ valable API &gt;= 29\n\n        \/\/ Cr\u00e9ation du fichier dans le stockage interne\n\n\n        \/\/ Via le resolver copie du fichier vers le r\u00e9pertoire externe\n        val une_url = URL(Uri.fromFile(fichier).toString())\n        val mime_type = \"text\/plain\"\n\n        val contentValues = ContentValues().apply {\n            put(MediaStore.MediaColumns.DISPLAY_NAME, nom_fichier)\n            put(MediaStore.MediaColumns.MIME_TYPE, mime_type)\n            put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)\n        }\n        val resolver = context.contentResolver\n        val uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)\n        if (uri != null) {\n            une_url.openStream().use { input -&gt;\n                resolver.openOutputStream(uri).use { output -&gt;\n                    input.copyTo(output!!, DEFAULT_BUFFER_SIZE)\n                }\n            }\n        }\n    }<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>et pour lire le fichier<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">fun lire_text_externe(context:Context, callback_texte:(texte_retour:String)-&gt;Unit={}) {\n\n\n    val nom_fichier = \"fichier_externe.txt\"\n    val chemin_download = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)\n    val fichier = File(chemin_download, nom_fichier)\n\n    var texte_fichier = \"\"\n\n    if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.Q) {\n\n        \/\/\/\/ valable API &lt;= 28 (n\u00e9cessite de d\u00e9finir les permissions de lecture dans AndroidManifest.xml)\n\n\n        if (fichier.exists()) {\n            texte_fichier = fichier.readText()\n        } else {\n            println(\"Fichier inexistant\")\n        }\n    } else {\n\n        \/\/\/\/ valable API &gt;= 29\n\n        \/\/ Via le contentResolver\n        val chemin_download = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)\n        val fichier = File(chemin_download, nom_fichier)\n        val resolver = context.contentResolver\n        val inputStream:InputStream? = resolver.openInputStream(Uri.fromFile(fichier))\n        val reader = BufferedReader(inputStream?.reader())\n        texte_fichier = reader.readText()\n\n    }\n\n    if (!texte_fichier.equals(\"\")) {\n        println(\"texte_fichier : $texte_fichier\")\n\n        \/\/ passage de texte JSON en liste de personnes\n        val stype = object : TypeToken&lt;List&lt;Personne&gt;&gt; () {}.type\n        val liste_personne:List&lt;Personne&gt; = Gson().fromJson&lt;List&lt;Personne&gt;&gt;(texte_fichier,stype)\n        \/\/ Affichage liste\n        for (une_personne in liste_personne) {\n            println (\"--&gt; $une_personne\")\n        }\n    } else {\n        println (\"pas de contenu existant\")\n    }\n\n\n}<\/code><\/pre>\n\n\n\n<p>Ressources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>les inputStream : <a rel=\"noreferrer noopener\" href=\"https:\/\/www.baeldung.com\/kotlin\/inputstream-to-string\" target=\"_blank\">https:\/\/www.baeldung.com\/kotlin\/inputstream-to-string<\/a><\/li>\n\n\n\n<li>utilisation du mediastore pour \u00e9crire : <a rel=\"noreferrer noopener\" href=\"https:\/\/medium.com\/@thuat26\/how-to-save-file-to-external-storage-in-android-10-and-above-a644f9293df2\" target=\"_blank\">https:\/\/medium.com\/@thuat26\/how-to-save-file-to-external-storage-in-android-10-and-above-a644f9293df2<\/a><\/li>\n\n\n\n<li>les types mimes : <a rel=\"noreferrer noopener\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Basics_of_HTTP\/MIME_types\/Common_types\" target=\"_blank\">https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Basics_of_HTTP\/MIME_types\/Common_types<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Compose_Banniere_PUB\"><\/span>Compose : Banni\u00e8re PUB<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A ce jour et par d\u00e9faut il n&rsquo;y a pas de composants avec Compose pour ajouter une banni\u00e8re pub. Il faut ajouter manuellement une vue via AndroidView.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">\/**\n * Composable d\u00e9di\u00e9 \u00e0 la pub de l'application\n * @param size Taille du bloc publicitaire\n * @param id Num\u00e9ro identification de l'appli pour la pub\n *\/\n@Composable\nfun BannerAds(size:AdSize, id:String) {\n    AndroidView(\n        factory = { context -&gt;\n            \/\/ Creates custom view\n            AdView(context).apply {\n                this.setAdSize(size)\n                this.adUnitId = id\n                this.loadAd(AdRequest.Builder().build())\n            }\n        }\n    )\n}<\/code><\/pre>\n\n\n\n<p>ce qui donne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"352\" height=\"143\" src=\"http:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-17.png\" alt=\"\" class=\"wp-image-4042\" srcset=\"https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-17.png 352w, https:\/\/blogperso.union31.fr\/wp-content\/uploads\/2022\/06\/image-17-300x122.png 300w\" sizes=\"auto, (max-width: 352px) 100vw, 352px\" \/><\/figure>\n\n\n\n<p>Resources :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/viede.dev\/jetpack-compose-admob-banner-adview\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/viede.dev\/jetpack-compose-admob-banner-adview\/<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/blog.blundellapps.co.uk\/using-admob-banner-ads-in-a-compose-layout\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/blog.blundellapps.co.uk\/using-admob-banner-ads-in-a-compose-layout\/<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Voir_%E2%80%A6\"><\/span>Voir &#8230;<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>voir les Composables ;<ul><li>le\u00e7ons d&rsquo;utilisation par google : <a rel=\"noreferrer noopener\" href=\"https:\/\/developer.android.com\/courses\/pathways\/compose\" target=\"_blank\">lien<\/a><\/li><li>les composants disponibles et mani\u00e8re de les programmer :<ul><li>pr\u00e9sentation google : <a rel=\"noreferrer noopener\" href=\"https:\/\/material.io\/components?platform=android\" target=\"_blank\">lien<\/a><\/li><li>autre sur github : <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/Foso\/Jetpack-Compose-Playground\" target=\"_blank\">lien<\/a><\/li><\/ul><\/li><\/ul>\n<ul class=\"wp-block-list\">\n<li>la r\u00e9cup\u00e9ration des ressources iages, ic\u00f4nes, etc..<\/li>\n\n\n\n<li>les variables remember et rememberState<\/li>\n\n\n\n<li>les threads\n<ul class=\"wp-block-list\">\n<li>thread vs coroutines : <a rel=\"noreferrer noopener\" href=\"https:\/\/www.baeldung.com\/kotlin\/threads-coroutines\" target=\"_blank\">lien<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>le positionnement des composables (en dehors des fichiers \u00ab\u00a0main\u00a0\u00bb)<\/li>\n\n\n\n<li>le principe d&rsquo;animation basique\n<ul class=\"wp-block-list\">\n<li>pr\u00e9sentation google : <a rel=\"noreferrer noopener\" href=\"https:\/\/developer.android.com\/jetpack\/compose\/animation\" target=\"_blank\">lien<\/a> <\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>l&rsquo;int\u00e9gration de composable tiers<\/li>\n\n\n\n<li>l&rsquo;utilisation en kotlin de biblioth\u00e8ques \u00e9crites en Java (graph et PDF)<\/li>\n\n\n\n<li><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>revoir comment d\u00e9clarer une classe \u00ab\u00a0singleton\u00a0\u00bb ;la navigation entre les vues<\/li>\n\n\n\n<li>les acc\u00e8s aux fichiers<\/li>\n\n\n\n<li>les autorisations (Internet, acc\u00e8s disques, etc)<\/li>\n\n\n\n<li>les transformations objet vers JSON et inversement\n<ul class=\"wp-block-list\">\n<li>lien : <a href=\"https:\/\/medium.com\/@hissain.khan\/parsing-with-google-gson-library-in-android-kotlin-7920e26f5520\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/medium.com\/@hissain.khan\/parsing-with-google-gson-library-in-android-kotlin-7920e26f5520<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><\/li>\n\n\n\n<li><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>En cours de r\u00e9daction Cours Google sur Kotlin avec Android: lien Classes Constructeur Il y a 2 types de constructeurs : les primaires et secondaires : Instenciation H\u00e9ritage Par d\u00e9faut une classe est de type \u00ab\u00a0final\u00a0\u00bb. Pour qu&rsquo;elle soit h\u00e9ritable<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-3884","post","type-post","status-publish","format-standard","hentry","category-_dev"],"_links":{"self":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts\/3884","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3884"}],"version-history":[{"count":115,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts\/3884\/revisions"}],"predecessor-version":[{"id":4198,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=\/wp\/v2\/posts\/3884\/revisions\/4198"}],"wp:attachment":[{"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3884"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3884"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogperso.union31.fr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3884"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}