Translate

mardi 23 avril 2013

Android Fragments

Introduits à partir de d’ANDROID 3.0 (API 11), les fragments permettent de développer des applications qui offriraient une navigation adaptée aussi bien à l’utilisation à partir d’un téléphone portable qu’à partir d’une tablette. Ci-dessous une figure exposant l’apport des fragments. Avec cette technique il est possible d’avoir une vue par écran sur les Smartphones et deux sur les tablettes. ANDROID Fragments Et parce que rien ne vaut un exemple, on réalisera ensemble et pas à pas une petite application météo. Cette application devra afficher une liste de pays. Le clic sur un élément de la liste, affichera les prévisions météo du pays en question. Nous allons la développer de sorte que sur un téléphone on aura la liste des pays sur tout l’écran, et le clic sur un élément démarrera une nouvelle activité qui affichera les prévisions météo. Du moment que sur une tablette, on aura la liste des pays et les prévisions sur le même écran. Le clic sur un pays mettra à jour les prévisions.
Pour résumer, nous aurons :
  • Vue1 : Liste des pays
  • Vue2 : Prévisions météo
Sur les Smartphones Vue1 ensuite Vue2. Cependant sur tablette Vue1 ET Vue2.
  • Chaque Vue est un Fragment qui dispose d’un fichier XML et d’une classe Java.
  • Certaines Activités afficheront, selon la taille de l’écran, un ou deux fragments. Donc ces dernières disposeront de deux fichiers XML.
  Retour à notre exemple. Dans notre cas nous aurons deux fragments list_pays_fragment et prevision_fragment. Nous aurons également deux activités list_pays_activity et prevision_activity. Le clic sur un pays, selon la taille de l’écran, démarrera l’activité et prevision_activity ou mettra directement à jour le fragment prevision_fragment. Donc list_pays_activity aura deux fichiers list_pays_activity.xml, l’un sous layout et l’autre sous layout-Large. Commençons par créer les layouts. Nous avons layout/list_pays_activity.xml qui devra afficher uniquement la liste des pays. Donc elle contiendra un seul fragment qui sera list_pays_fragment.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ListPaysActivity">
<fragment
android:id="@+id/list_pays_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.tutometeo.ListPaysFragment">
</fragment>
</LinearLayout>

Nous avons layout-large/list_pays_activity.xml qui devra afficher la liste des pays et les prévisions. Donc elle contiendra deux fragments list_pays_fragment et prevision_fragment.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ListPaysActivity">
<fragment
android:id="@+id/list_pays_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.example.tutometeo.ListPaysFragment">
</fragment>
<fragment
android:id="@+id/prevision_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.example.tutometeo.PrevisionFragment">
</fragment>
</LinearLayout>

La liaison entre un fragment et la classe correspondante se fait par le biais de l’attribut class de la balise fragment. Ceci veut dire c’est la classe ListPaysFragment qui chargera le contenu de list_pays_fragment.xml dans ce fragment. Sans oublier que nous avons layout-Large/list_pays_activity.xml qui devra afficher la liste des pays et les prévisions météo. NB : Pour le reste du code source consultez le code source ici. Passons maintenant aux classes, et commençons par les fragments.java. ListPaysFragment.java On commence par charger le contenu du fichier list_pays_fragment.xml dans le fragment.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.list_pays_fragment,
container, false);
ListView listPays = (ListView) view.findViewById(R.id.list_pays);
listPays.setAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, pays));
listPays.setOnItemClickListener(selectPays);
return view;
}

Ensuite nous informons l’activité que nous souhaitons consulter les prévisions d’un pays donné. Pour pouvoir le faire nous allons devoir créer une interface OnPaysSelected qui sera implémentée par la classe de l’activité. Cette interface nous permettra d’appeler les méthodes qui y sont déclarées et qui ont été implémentées par l’activité.

public interface OnPaysSelected {
/**
* @param name
* Nom du pays sélectionné sur la liste.
*/
public void paysSelect(String name);
}

Maintenant il ne reste plus qu’à attaché ce listner à notre activité pour pouvoir communiquer avec elle.

private OnPaysSelected paysFragListener;
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
paysFragListener = (OnPaysSelected) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " doit implementer OnPaysSelected ");
}
}

Il ne reste plus qu’à faire appel à la méthode paysSelect(String).

private OnItemClickListener selectPays = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
paysFragListener.paysSelect(pays[arg2]);
}
};

Passons maintenant à la chose la plus importante : comment savoir si l’on doit mettre à jour un fragment déjà à l’écran ou lancer une nouvelle activité ? On commence par récupérer le fragment. Ensuite on vérifie s’il est déjà affiché ou pas.

public void paysSelect(String region) {
//On récupère le fragment PrevisionFragment
PrevisionFragment fragment = (PrevisionFragment) getSupportFragmentManager() .findFragmentById(R.id.prevision_fragment);
//Si le fragment est déjà à l'écran on le met à jour (tablette), si non on démarre une nouvelle activité (Smartphone).
if ((fragment != null) && fragment.isInLayout()) {
fragment.setMsg("Prévision de " + region + " dans un fragment mis à jour");
} else {
Intent intent = new Intent(this, PrevisionActivity.class);
intent.putExtra(PrevisionActivity.MSG_EXTRAS, "Prévision de " + region + " dans une nouvelle activité");
startActivity(intent);
}
}

J’ai essayé de commenter au mieux le code source. Si vous avez des questions n’hésitez pas à poster vos commentaires.

2 commentaires: