Monthly Archives

3 Articles
Preview Android Jelly Bean

Preview Android Jelly Bean

Bonsoir, c’est un peu à chaud que je vais aborder avec vous, rapidement, les principales nouveautés d’Android Jelly Bean (version 4 .1). Sachez quand même que je n’ai pas pu voir la keynote de ce soir donc j’ai regardé tout aussi rapidement les nouveautés via Twitter et via le SDK déjà disponible au téléchargement.

Je vais vous présenter d’abord les nouveautés pour l’utilisateur puis ensuite celles pour les développeurs. La plupart des images que vous verrez sont prises à partir de l’émulateur et vu qu’elle est encore au stade de beta, d’autres nouveautés ne sont pas encore connues.

Note aux développeurs :

Pour utiliser l’émulateur, lorsque vous arrivez sur le home et que vous avez un fond noir (100% des cas). Faites les étapes suivantes :

  • Ouvrez la barre de notification
  • Cliquez sur le bouton paramètres
  • Appuyez sur le bouton Home
  • Et voilà

Nouveautés d’Android 4.1 :

Dans les nouveautés, je vais vous parler très brièvement de la partie home car elle n’a pas réellement changée. La seule « grosse » nouveauté concerne les widgets. Quand vous voulez les placer et, si un raccourci de l’application gène, Android va le décaler sur le côté pour laisser la place au Widget. Très utile pour les placer plus rapidement et éviter le message « Oups, plus assez de place ».

Voici la nouvelle Home.. Euh en fait non

La barre de notification quant à elle est devenue très sobre. Finie la transparence pour voir derrière la home. Tout est noir. En tout cas, ça rend très bien avec les notifications.

Mais qui est cette Dianne?

On notera aussi une évolution du clavier qui n’est pas sans rappeler celui d’HTC à ses débuts sur Sence. ou celui fournit avec Android 2.3 Mais il a la particularité d’être enfin prédictif et ce très efficacement. Je pense que SwiftKey et autres claviers prédictifs n’ont qu’à bien se tenir d’ici là.

Rien à redire.

Maintenant nous arrivons sur Google Maps. Je n’ai pas pu tout voir car l’émulateur est assez capricieux. Sachez juste que sur la version installée, il est enfin possible de télécharger simplement une portion de la map pour avoir par exemple le GPS en offline. (Oui je sais, avant on pouvait le faire via le labs).

Mais trop bien!!!

On notera aussi la présence d’un nouvel Easter Egg pour Jelly Bean mais ça, je vous laisse le découvrir.

L’une des nouveautés qui fera plaisir aux utilisateurs avec un petit forfait data est que lors d’une mise à jour de l’application, ce n’est plus toute l’application mise à jour qui est téléchargée mais juste les fichiers impactés. Fini les 3Mo de téléchargement pour juste un petit Fix Bug.

Vous pouvez aussi dès maintenant, et ce pour toutes les versions d’Android, supprimer et mettre à jour, directement depuis le play Store Web, vos applications. 

Et si je mettais à jour chrome??

Dans les autres nouveautés que je n’ai pas pu tester on notera aussi :

  • Nouvelle version de Google+
  • Nouvelle version de Youtube
  • Meilleure fluidité globale du système
  • L’ajout d’une secrétaire : Google Now
  • Possibilité de coller plusieurs photos ensemble directement à partir de l’appareil Photo.
  • Et pleins d’autres que je n’ai pas encore vu.
 

Côté Développeurs

De ce côté-ci, il y en a à la pelle donc je vais juste indiquer les quelques-unes qui m’ont marquées :

Le service de push C2DM sort de la phase de Beta et devient GCM pour Google Cloud Message. Plus de formulaire à remplir mais  une clé API à générer pour chacune de vos applications et une library externe à rajouter à votre projet. De plus, Google annonce qu’il n’y aura plus de limite de taille (limitée à 200 caractères environs avant) ni de limite d’envoi de push. Ce n’est pas une bonne nouvelle ? Et cerise sur le gâteau, GCM est compatible Android 2.2+ (tout comme son aïeux C2DM). 

Maintenant, on peut passer simplement des options à nos activitées comme le fait de rajouter des animations pour le lancement et la fermeture.

On peut indiquer directement dans le Manifest l’Activity parente d’une autre activité pour un retour rapide grâce au bouton retour.

Les notifications ont deux tailles disponibles : BIG et NORMAL. De plus, on peut les mettre à jour facilement et en fonction du cas, rediriger sur le bon Intent. On peut aussi faire des notifications que image, que texte ou texte + image. Et pour finir les notifications en beauté. Si vous avez un appel ou un sms dans les notifications, vous pouvez répondre/rappeler directement si vous le souhaitez.

Inclusion  d’une nouvelle déclaration dans le Manifest pour les appareils qui sont dédiés à l’affichage de l’interface utilisateur sur un écran de télévision: FEATURE_TELEVISION.

On peut Maintenant rattacher un ClipDataObject (Copier/Coller) directement à un intent via la méthode setClipData().

Ajout de la méthode isActiveNetworkMetered() qui indique si oui ou non on a un réseau disponible et qui plus est fonctionnel.  

Et pleins d’autres nouveautés que je n’ai pas encore eu le temps de voir.

Conclusion

Bref, ce petit aperçu de Jelly Bean m’a vraiment mis l’eau à la bouche. L’api se complète enfin avec des méthodes simples qui évitent de faire une méthode bancale (test du réseau par exemple). De plus l’OS en lui-même se bonifie avec le temps en proposant toujours plus de fonctionnalités utiles et pratiques et qui permettent à l’utilisateur final de se simplifier la vie.

Google prouve qu’Android n’est plus réservé aux Geeks mais qu’il peut être utilisé par le grand public avec une grande facilité. Il l’avait déjà prouvé avec l’ancienne version mais avec la nouvelle, c’est encore mieux. Il ne reste plus qu’à prier pour que les constructeurs suivent le pas et ne fassent pas la même erreur que pour les anciennes versions non arrivées.

Gérer des événements dans une listeview (màj).

Gérer des événements dans une listeview (màj).

Bonjour à tous!

J’ai appris une nouvelle façon, plus facile, plus propre surtout, et plus « avantageuse » de gérer plusieurs événements sur une ligne dans une liste.

Souvenez-vous, j’avais réalisé et utilisé une classe qui nous gérait nos actions, aujourd’hui, nous utiliserons que le système Androïd et ses propres outils !

public class TutoAdapterActivity extends Activity {

    private ListView listview;
    private ArrayList<BeanRow> grpBr;
    private OnClickListener onClick;
    private MySecondeAdapter adapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        grpBr = new ArrayList<BeanRow>();
        BeanRow br1 = new BeanRow("Laurent", "Fritte7", false, 0);
        BeanRow br2 = new BeanRow("Benjamin", "Throrin's", false, 1);
        grpBr.add(br1);
        grpBr.add(br2);

        listview = (ListView) findViewById(R.id.listView);
        //MyAdapter adapter = new MyAdapter(getApplicationContext(), R.layout.row_tourne, grpBr);
        onClick = onClick();
        adapter = new MySecondeAdapter(getApplicationContext(), R.layout.row_tourne, grpBr, onClick);
        listview.setAdapter(adapter);
    }
}

Je n’ai rien modifié dans mon objet (liste) et mes actions seront toujours les mêmes ! Ainsi que ma vue, ce n’est que l’adapter qui changera. Tout d’abord, le constructeur change un peu, nous lui donnons un listener, que nous verrons plus tard. Allons de suite dans le nouvel adapter.

public class MySecondeAdapter extends BaseAdapter {

    private ArrayList<BeanRow> liste;
    private OnClickListener click;
    private LayoutInflater inflater;
    private int idView;
    private Holder holder;
    private Context ct;

    public MySecondeAdapter(Context applicationContext, int rowTourne,
            ArrayList<BeanRow> grpBr, OnClickListener onClick) {
        ct = applicationContext;
        liste = grpBr;
        click = onClick;
        inflater = LayoutInflater.from(applicationContext);
        idView = rowTourne;
    }

    /**
     * Ici on recupere la vue ou on la cree
     */
    public View getView(int position, View view, ViewGroup parent) {
        if (view == null) {
            holder = new Holder();
            view = inflater.inflate(idView, null);
            holder.rowIcon = (ImageView) view.findViewById(R.id.iconRow);
            holder.rowPrenom = (TextView) view.findViewById(R.id.prenomTextView);
            holder.rowPseudo = (TextView) view.findViewById(R.id.pseudoTextView);
            holder.rowAction = (ImageButton) view.findViewById(R.id.imageAction);
            holder.rowCheck = (CheckBox) view.findViewById(R.id.checkBoxRow);

            /** la vue etant cree, nous rajoutons le listener */
            holder.rowAction.setOnClickListener(click);
            holder.rowCheck.setOnClickListener(click);
            holder.rowPrenom.setOnClickListener(click);
            view.setTag(holder);
        } else {
            holder = (Holder) view.getTag();
        }
        /** je donne la position a holder, plus facile a recuperer dans le listener */
        holder.position = position;
        holder.rowPrenom.setText(liste.get(position).getPrenom());
        holder.rowPseudo.setText(liste.get(position).getPseudo());
        holder.rowCheck.setChecked(liste.get(position).isCheck());
        holder.rowIcon.setImageDrawable(switchIcon(liste.get(position).getPos()));

        boolean check = holder.rowCheck.isChecked();
        /** on redessine l'animation si coché = grisé ! */
        if (check) {
            AlphaAnimation anim = new AlphaAnimation(1, 0.2f);
            anim.setDuration(0);
            anim.setFillAfter(true);
            view.startAnimation(anim);
        } else {
            AlphaAnimation anim = new AlphaAnimation(0.2f, 1);
            anim.setDuration(0);
            anim.setFillAfter(true);
            view.startAnimation(anim);
        }

        return view;
    }

    private Drawable switchIcon(int pos) {
        Drawable icon = null;
        switch (pos) {
        case 0:
            icon = ct.getResources().getDrawable(R.drawable.labo_48x48);
            break;
        case 1:
            icon = ct.getResources().getDrawable(R.drawable.user_48x48);
            break;
        }
        return icon;
    }

    public int getCount() {
        return liste.size();
    }

    public BeanRow getItem(int position) {
        return liste.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

} 

J’ai commenté le code, pour plus de compréhension, mais nous voyons, qu’il créé une vue sur base d’une classe qui est un « mapping de l’xml » tout simplement, et nous lui donnons comme tag, l’objet en lui-même, sans oublier la position quand on récupère la vue (cela facilite la récupération dans la liste).

Nous définissons les champs qui ont besoin du listener et nous définissons une règle simple sur le checkbox, s’il est coché, on le grise, sinon on fait rien. C’est tout pour l’adapter, les événements sont gérés dans l’activity (ou une classe encore a part si on veut avoir un modèle MVC).

Voici les actions, nous constatons que je fais un switch, sur les id (de l’xml) des vues.

/**
 * Un simle listener qui gère tous les evenements de votre vue.
 * @return
 */
private OnClickListener onClick() {
    OnClickListener event = new OnClickListener() {
        public void onClick(View v) {
            View parent;
            Holder holder;

            switch (v.getId()) {

                /** Ici nous devons remonter dans la hiérarchie de la vue (dans l'xml) */
                case R.id.imageAction:
                    /** v = imagebouton */
                    parent = (View) v.getParent();
                    /** parent = le linearlayout */
                    parent = (View) parent.getParent();
                    /** parent = la vue xml qui a le Holder en tag */
                    holder = (Holder) parent.getTag();
                    Toast.makeText(getApplicationContext(), "Le pseudo de la ligne: " + grpBr.get(holder.position).getPseudo(), Toast.LENGTH_SHORT).show();
                    break;

                case R.id.checkBoxRow:
                    /** v = le checkbox */
                    parent = (View) v.getParent();
                    /** parent = la vue xml qui a le Holder en tag */
                    holder = (Holder) parent.getTag();
                    CheckBox check = (CheckBox) v;
                    if (check.isChecked()) {
                        grpBr.get(holder.position).setCheck(true);
                    } else {
                        grpBr.get(holder.position).setCheck(false);
                    }
                    /** on notifie le changement de la liste pour que le check se met à jour */
                    adapter.notifyDataSetChanged();
                    break;

                case R.id.prenomTextView:
                    /** v = textview */
                    parent = (View) v.getParent();
                    /** parent = linearlayout */
                    parent = (View) parent.getParent();
                    /** parent(écrasé) = la vue xml qui a le tag Holder */
                    holder = (Holder) parent.getTag();
                    Toast.makeText(getApplicationContext(), "Le prenom de la ligne: " + grpBr.get(holder.position).getPrenom(), Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
    return event;
}

Étant donné que lorsqu’on fait view.getId(), nous récupérons l’id de la vue ainsi, nous pouvons tester la valeur et définir nos événements. Ensuite, il faut suivre la hiérarchie de votre vue xml, c’est pourquoi je fais des view.getParent(), c’est pour monter dans la hiérarchie.

Je peux ainsi, remonter à la base, et récupérer mon tag, qui n’est autre que l’objet Holder de l’adapter. On récupère les données et la position sans problème, et nous lançons les événements.

Voilà, j’espère avoir été plus clair que la dernière fois, et que vous préfériez cette méthode-ci. Je vous ai ré-uploadé sur code.google le projet complet, avec les deux adapters.

Le thème Holo pour tous

Le thème Holo pour tous

Aujourd’hui, je ne vais pas vous faire un tutoriel pour profiter du thème Holo dans vos applications quand vous êtes sur de vielles versions mais d’une library faisant exactement ceci.

Je viens de l’essayer et ma fois, après quelques réécritures minimes (surcharges de thèmes perso et surcharge des Dialogs) je peux vous dire qu’elle marche très très bien.

Cette library s’appelle HoloEverywhere et elle est disponible sur ce GitHub.

Je ne vais pas entrer dans les détails d’installation, ils l’expliquent très bien. Je vais juste vous montrer que, ça marche très bien même si je note de petites différences avec le thème Holo original.

Seul gros bémol, la taille supplémentaire que prendra votre application à la suite de l’inclusion de cette library : comptez entre 400Ko et 1Mo de plus d’espace pris lorsque votre application est installée sur un smartphone. Cette taille s’explique car, pour pouvoir reproduire ce thème, ils ont dû intégrer les images de chaque élément graphique utilisés par Android.

Voici un exemple d’applis que j’ai fait. Il s’agit d’un questionnaire tout bête avec pleins de champs les uns à la suite des autres. La première image montre l’aperçu sur Android 4.0.3 et le second ce que ça donne, sans HoloEverywhere, sur Android 2.1. Le dernier screen quand à lui montre le résultat sur Android 2.1 avec la library. Bluffant n’est-ce pas ? 

Formulaire sous Android ICS

Aperçu sous Android 2.1 sans HoloEverywhere

Aperçu sur Android Eclair avec la library