Tag Archives: Développement

ParcelableCodeGenerator

If you are used to coding Android applications, there is a good chance that you had to write some Parcelable classes.

A quick reminder about Parcelable : It’s an interface you can implement on your classes. If you do so, you can then store the whole class in a Bundle or as an Intent extra.
My webservice library, DataDroid, use Parcelable objects to retrieve the result from the webservices if you don’t use a Database to store your data.

There is one downside with Parcelable … You need to write a LOT of boilerplate to implement the Parcelable interface in your class. And as every good software engineer, I’m lazy :D
Which brings us to ParcelableCodeGenerator !!

You can find all the information on its GitHub page, but here is a short explanation :

  • You clone the repository and import the Java project in Eclipse (or your favorite IDE)
  • You write a JSON file defining your Parcelable class in the input folder (you can use subfolders to sort your files). Examples are provided to learn the syntax
  • You run the project as a Java Project
  • The corresponding classes are “magically” generated in the output folder ready for you to copy them in your project

It’s really easy to use and it’s going to save you a lot of time.

Last important thing : the project license. As all my other projects, it is released under the Beerware license :

You can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return.

ContentProviderCodeGenerator or how to create your ContentProviders easily

There are multiple ways to store data persistently in Android, like for example the SharedPreferences. One of them is to use a ContentProvider.

A ContentProvider is one of primary building blocks of Android applications, providing content to applications. You can for example use it to open some of your data to other applications.
You can also use it to just store your data and not export it to other applications (by setting the flag android:exported="false" in your Android Manifest).

Write your first ContentProvider can be a challenging task as there are a good number of methods to implement and it’s not always clear how to do it.
That was one of the reason why I released with DataDroid (my local and remote data management library) some skeletons explaining how to do it by just following a bunch of TODOs to follow.

However you still have a lot of code to write, most of it just being copy/paste all over the classes. And when you start having multiple versions of your ContentProvider with new columns or tables, it begins to be really annoying to have to maintain that…

Which brings us to ContentProviderCodeGenerator !!

Like every lazy software engineer, it was bothering me and so I took/found some time and wrote a code generator ! :)

You can find all the information on its GitHub page, but here is a short explanation :

  • You clone the repository and import the Java project in Eclipse (or your favorite IDE)
  • You write a JSON file defining your tables and their columns in the input folder. Examples are provided to learn the syntax
  • You run the project as a Java Project
  • All the needed files are “magically” generated in the output folder ready for you to copy them in your project

It’s really easy to use (and if needed I can help you)
It makes adding a column or a table so easy it’s not even funny.
It just works. (yes I know I just used an Apple slogan on an Android blog) (and if it doesn’t work, I’ll fix it)

Last important thing : the project license. As all my other projects, it is released under the Beerware license :

You can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return.

TimePickerDialog and AM/PM vs 24 Hour format

Just a short article to maybe help other people not spend 1 hour searching the web for the answer like I did.

The Android SDK provides you with 2 really well made dialog pickers for respectively a date and a time : DatePickerDialog and TimePickerDialog.

The constructors for DatePickerDialog are pretty much straight-forward.
However the one for TimePickerDialog has a small problem :

As you can see in the screenshot above, you need to specify through the is24HourView parameter whether you want to display a time with hours from 0 to 23 (used in France and Germany for example) or you want to display a time with hours from 1 to 12 and also AM/PM selector (used in the USA for example).

The main problem is that I don’t want to choose that in my code. I want it to be linked to the user locale settings like everythink else.
I don’t want why it was coded like that but here is how to link this parameter to the user locale :

    new TimePickerDialog(this, mOnTimeSetListener, time.hour, time.minute, DateFormat.is24HourFormat(this));

The method is24HourFormat from DateFormat allows us to retrieve the user setting.

How to add autocompletion to an EditText

Finally after months and months of saying that I would add development articles to my blog, here is the first one :)

EditText is a component that everybody knows and it is the primary way to get user input in an Android application.
What is really less known is its cousin : AutoCompleteTextView. It’s a subclass of EditText that allows you to display possible autocompletions to the user depending on what he/she already entered in the EditText.

This article will focus on how to use this component and how to bind different data sources to provide the completions.

1 – Presentation of AutoCompleteTextView and simple autocompletion

AutoCompleteTextView is used exactly the same way as an EditText in your layouts (as it’s a subclass of EditText). You just need to replace your EditText by an AutoCompleteTextView and this part is done !

Now that our layout is ready, let’s look at the code.

For this first example we are going to use a really simple example (based on the documentation of AutoCompleteTextView class in the Android SDK). The possible autocompletions are going to be a fixed list of countries.

1
2
3
4
5
6
7
8
private static final String[] COUNTRIES = new String[] {
	"Belgium", "France", "Italy", "Germany", "Spain"
};
 
// In the onCreate method
AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.actv_country);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, COUNTRIES);
textView.setAdapter(adapter);

We just have an array of Strings as the data source and we just bind via an ArrayAdapter the list of countries> The component will manage them by itself.

Now let’s look at a little more complex example.

2 – Email autocompletion

Let’s say we have a login screen in our application where the login is an email. An email is quite long and really annoying to type in, especially with a virtual keyboard.

We don’t know all the email addresses the user could potentially have. What we know however from his phone is all the email addresses he/she used as an account (Google, Facebook, Twitter, …).
We can use them as a data source to provide completion.

1
2
3
4
5
6
7
8
9
10
11
12
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$", Pattern.CASE_INSENSITIVE);
 
// In the onCreate method
AutoCompleteTextView editTextLogin = (AutoCompleteTextView) findViewById(R.id.actv_login);
Account[] accounts = AccountManager.get(this).getAccounts();
Set<String> emailSet = new HashSet<String>();
for (Account account : accounts) {
	if (EMAIL_PATTERN.matcher(account.name).matches()) {
		emailSet.add(account.name);
	}
}
editTextLogin.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, new ArrayList<String>(emailSet)));

This time instead of using a fixed array of Strings, we load the user accounts through the AccountManager.
As some accounts may not have an email address linked to them, we filter them and keep only the ones who matches an email regex. We also use a Set to remove the duplicates.
Then we use the same way as before to bind them to the AutoCompleteTextView through an ArrayAdapter.

One thing to know if you want to use this snippet of code as is in your project : it requires the permission android.permission.GET_ACCOUNTS to be able to read the user accounts.

You can use this example with any other data source as long as you manage to get an array of Strings to display.

And here is how it looks :

3 – Webservice autocompletion

For the first 2 examples, we only used static data. Now let’s use dynamic data for the auto-completion. The data is going to be returned from a web service which is going to be called every time the user input changes in the field.
For this example, we are going to write the code to add autocompletion to an address field :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
AutoCompleteTextView editTextAddress = (AutoCompleteTextView)findViewById(R.id.actv_address);
editTextAddress.setAdapter(new AutoCompleteAdapter(this));
 
// And the corresponding Adapter
private class AutoCompleteAdapter extends ArrayAdapter<Address> implements Filterable {
 
	private LayoutInflater mInflater;
	private Geocoder mGeocoder;
	private StringBuilder mSb = new StringBuilder();
 
	public AutoCompleteAdapter(final Context context) {
		super(context, -1);
		mInflater = LayoutInflater.from(context);
		mGeocoder = new Geocoder(context);
	}
 
	@Override
	public View getView(final int position, final View convertView, final ViewGroup parent) {
		final TextView tv;
		if (convertView != null) {
			tv = (TextView) convertView;
		} else {
			tv = (TextView) mInflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
		}
 
		tv.setText(createFormattedAddressFromAddress(getItem(position)));
		return tv;
	}
 
	private String createFormattedAddressFromAddress(final Address address) {
		mSb.setLength(0);
		final int addressLineSize = address.getMaxAddressLineIndex();
		for (int i = 0; i < addressLineSize; i++) {
			mSb.append(address.getAddressLine(i));
			if (i != addressLineSize - 1) {
				mSb.append(", ");
			}
		}
		return mSb.toString();
	}
 
	@Override
	public Filter getFilter() {
		Filter myFilter = new Filter() {
			@Override
			protected FilterResults performFiltering(final CharSequence constraint) {
				List<Address> addressList = null;
				if (constraint != null) {
					try {
						addressList = mGeocoder.getFromLocationName((String) constraint, 5);
					} catch (IOException e) {
					}
				}
				if (addressList == null) {
					addressList = new ArrayList<Address>();
				}
 
				final FilterResults filterResults = new FilterResults();
				filterResults.values = addressList;
				filterResults.count = addressList.size();
 
				return filterResults;
			}
 
			@SuppressWarnings("unchecked")
			@Override
			protected void publishResults(final CharSequence contraint, final FilterResults results) {
				clear();
				for (Address address : (List<Address>) results.values) {
					add(address);
				}
				if (results.count > 0) {
					notifyDataSetChanged();
				} else {
					notifyDataSetInvalidated();
				}
			}
 
			@Override
			public CharSequence convertResultToString(final Object resultValue) {
				return resultValue == null ? "" : ((Address) resultValue).getAddressLine(0);
			}
		};
		return myFilter;
	}
}

As the data is dynamic depending on the current value, we can’t just provide beforehand the list of elements. Instead we create an ArrayAdapter with a special Filter.
Everytime the input changes, the performFiltering method is called and we retrieve in it the corresponding values from the webservice. These values are then transfered through the FilterResults object to the publishResults method where we replace the current elements with the new ones.

In our specific case, our webservice is the SDK Geocoder which calls the Maps server to get possible addresses based on input provided by the user.
As the result type, Address, is a complex object and we only want to display its formatted address while still keeping the object in the Adapter for further use, we also have to override both getView and convertResultToString methods :

  • The first one, getView, to choose how to display our special object in the list of possible autocompletions.
  • convertResultToString is used internally by the AutoCompleteTextView to choose what to display in the EditText field when the user selects one of the completions (in our case, the formatted address).

If the data returned by your webservice is only a String, you don’t need to do that (except if you want a special format, like upper case or something).

One thing to remember, the code in the performFiltering method is executed in a worker thread so we can directly access the webservice (in our case the Geocoder) to get the corresponding results even if it’s a long process.

4 – Conclusion

Normally now you know how to add autocompletion to your applications :)

If you have some questions about it, feel free to comment this article or to contact me via email !

And I have made a small application containing all these examples. Here is the APK and the project source code.

Tutorial : utilisation des projets Android library

Ce tutoriel suppose que vous utilisiez Eclipse en version 3.5.2 (la version 3.6 est déconseillé pour le plugin Android), le SDK en révision 7 et le plugin ADT pour Eclipse en version 0.9.8

Cet article a pour objectif d’expliquer ce que sont et comment utiliser les Android library dans vos projets Android.

Présentation

Cette fonctionnalité relativement récente (intégré au SDK en mai 2010 avec la révision 6) permet de factoriser du code commun à plusieurs applications et donc de profiter d’une réutilisabilité plus forte de vos développements.

Elle est compatible avec les versions d’Android suivantes : 1.5, 1.6, 2.1 et 2.2.

La grande différence par rapport à l’utilisation d’un JAR contenant son code source est que les projets library Android permettent également de factoriser les ressources (layout, drawable, …) et donc de pouvoir réutiliser également des Activities ou des Providers !

Par exemple dans le cas d’une application disponible en version gratuite et payante, toute la partie commune peut être mise dans un projet library. Les 2 versions, payante et gratuite, vont inclure cette library et vont seulement ajouter le mécanisme spécifique de leur version : des pubs dans la version gratuite et le mécanisme de vérification d’achat réel de l’application dans la version payante par exemple.

Le code est du coup beaucoup plus simple à maintenir plutôt que de devoir continuellement copier/coller du code entre les 2 applications à chaque modification de la partie commune.

Au niveau architecture, un projet library Android ne se différencie pas, ou très peu, d’un projet standard Android. Il contient également un fichier manifest, des dossiers src/ et res/. Il est possible d’inclure des layout ou de stocker des images via le dossier standard drawable. Le code source peut utiliser ces ressources via la classe R standard.

Un projet library Android n’est par contre pas compilable en l’état en un fichier .apk. De la même façon, il n’est pas possible d’exporter ce projet sous la forme d’un JAR. A la place, il faut le référencer dans un projet standard Android qui va, lui, générer l’application complète. Il est par contre totalement possible d’intégrer une library JAR dans un projet library et même de référencer un projet library dans une projet library (mais on y reviendra plus tard dans l’article)

Cette génération va fusionner les sources provenant du projet principal et celle venant du projet library. Les ressources (contenu dans le dossier res/) seront également fusionnées. Si une ressource a la même ID dans le projet principal et le projet library, c’est celle du projet principal qui aura la priorité. Cela va permettre entre autres de surcharger des ressources.

Un projet peut référencer sans problème plusieurs projets library. Cela va permettre de segmenter son projet encore mieux. Comme on le verra tout à l’heure, il va être possible de prioriser un projet library par rapport à une autre (cela est principalement utile pour les ressources).

Les ressources du projet final ayant la priorité, si vous ne voulez pas que quelqu’un qui inclut votre librairie écrase une de vos ressources par erreur en en ajoutant une avec le même nom dans son projet, penser à utiliser des noms spéciaux ou encore mieux à préfixer toutes vos ressources par un identifiant spécifique à votre projet.

Création d’un projet library

La création d’un projet library est en tout point identique à la création d’un projet standard Android. Une fois ce projet créé (nommé dans le cas de ce tutoriel AndroLibFirst), nous allons changer un paramètre afin de transformer ce projet standard en projet library:

  1. Dans l’onglet Package Explorer , faire un clic droit sur le projet et choisir Properties.
  2. Dans la fenêtre qui s’ouvre, choisir la section “Android”. On remarque alors la présence d’une section Library en bas de la fenêtre
  3. Cocher la case “Is Library” et cliquer sur Apply.
  4. Valider les changements en cliquant sur le bouton OK.

Le projet est maintenant devenu un projet library ! Il est maintenant possible de le référencer dans un projet principal.

Gestion du fichier manifest d’un projet library

De la même façon que pour un projet standard, le fichier manifest doit définir les composants partagés de la librairie : les Activities, les Providers, …

Référencer un projet library dans le projet principal

Dans l’interface qu’on vient d’utiliser pour transformer notre projet standard en projet library, on remarque qu’il y a 4 boutons : Add, Remove, Up et Down. Ils vont permettre d’ajouter ou de retirer une référence vers un projet library et d’ordonner les références aux projets library entre elles. Il faut savoir que la librairie la plus haute dans la liste est prioritaire sur celles qui la suivent et que les ressources sont donc choisies en fonction de ces priorités.

Pour ajouter un référence vers notre projet AndroLibFirst depuis notre projet principal AndroLibMain, les actions sont les suivantes :

  1. Dans l’onglet Package Explorer , faire un clic droit sur le projet et choisir Properties.
  2. Dans la fenêtre qui s’ouvre, cliquer sur le bouton Add. Une popup s’ouvre alors montrant la liste des projets library disponibles dans le workspace.
  3. Choisir le projet AndroLibFirst que l’on veut référencer et cliquer sur le bouton OK.
  4. Validez les changements en cliquant sur le bouton OK.

La référence est alors mise en place par Eclipse et le code et les ressources du projet library(encadrés en bleu ci-dessous) sont maintenant accessibles dans le projet principal comme on peut le voir dans ce screenshot :

Gestion spéciale des composants library dans le fichier manifest du projet standard

Les composants du projet library que l’on veut rendre accessible dans l’APK final doivent être redéfini dans le manifest afin qu’ils soient pris en compte lors de la création de l’APK.

Cela concerne les balises <activity>, <service>, <receiver>, <provider> ainsi que les <permission> et <uses-library> entre autres. Les déclarations doivent utiliser les noms complets avec les packages afin qu’ADT puisse savoir exactement où chercher les éléments.

Fonctionnement spécial : l’imbrication des projets library

On va commencer ici à s’amuser un peu en s’amusant à enchaîner les projets library.

Exemple : un projet principal qui référence un projet library (jusque là c’est standard), qui lui-même référence un projet library qui peut lui aussi référencer un projet library, etc, etc, etc … (Toute ressemblance avec Inception n’est que pur coïncidence. On pourrait parler d’Androidception !)

Avant de voir comment faire cela, une chose à savoir ! Cela ne fonctionne que depuis la toute récente (hier soir) mise à jour du SDK et du plugin ADT. Il faut donc avoir le SDK révision 7 et le plugin ADT en version 0.9.8. Mettez à jour votre environnement avant de tester cette nouvelle fonctionnalité donc

Prenons un exemple bidon : un projet principal AndroLibMain qui inclut un projet library AndroLibFirst qui lui-même inclut un projet library AndroLibSecond. Le projet AndroLibMain contient une classe LibMain qui étend la classe LibFirst du projet AndroLibFirst qui elle-même étend la classe LibSecond du projet AndroLibSecond. Totalement inutile comme fonctionnement mais cela ira très bien comme exemple. Voyons maintenant comment réaliser cela :

  1. Pour commencer, on va créer nos 3 projets sans se soucier de savoir si ce sont des projets library ou non
  2. Une fois cela fait, on commence par transformer le projet AndroLibSecond en projet library. Pour ceux qui ont oublié comment faire, remonter un peu dans l’article pour trouver la marche à suivre
  3. On attaque ensuite la nouveauté ! A savoir transformer le projet AndroLibFirst en projet library et référencer dans celui-ci le projet AndroLibSecond.
    1. Pour la partie, transformer le projet en projet library, on fonctionne comme précédemment.
    2. Pour ajouter le projet library AndroLibSecond, on remarque que la zone d’ajout d’un projet library n’est pas grisé (ce qui était le cas avant la mise à jour du SDK r7 et du plugin ADT en version 0.9.8). Il nous suffit d’ajouter le projet library comme expliqué précédemment.
    3. On valide le tout. On a donc désormais un projet library AndroLibFirst référençant le projet AndroLibSecond
  4. Pour finir, il nous faut référencer ce projet AndroLibFirst dans le projet principal. On ajoute donc cette référence comme précédemment.
  5. Et la surprise ! Le projet principal AndroLibMain contient désormais une référence vers le projet AndroLibFirst ce qui est logique mais aussi vers le projet AndroLibSecond. Le plugin ADT s’est chargé de reporter le référence entre le projet AndroLibFirst et AndroLibSecond afin que lors de la création de l’apk du projet principal toutes les librairies nécessaires soient présentes !

Le résultat est donc le suivant :

On voit donc dans le projet AndroLibFirst les éléments entourés en bleu du référence du projet AndroLibSecond


Dans le projet principal, on a en vert les éléments du référencement direct du projet AndroLibFirst et en rouge les éléments indirectement référencés du projet AndroLibSecond

Migration des projets library de ADT 0.9.7 à 0.9.8

Afin de pouvoir gérer l’imbrication des projets library, le fonctionnement des projets library a été revu entre la version 0.9.7 et 0.9.8 du plugin ADT. La conséquence de cette modification est que si vous ouvrez un workspace ayant un projet library après avoir mis à jour le plugin ADT, vous allez tomber sur ce problème :

La référence MyLibrary est celle d’ADT 0.9.7 tandis que MyLibrary_src est celle d’ADT 0.9.8. Il faut donc déréférencer l’ancienne. Pour cela, les étapes à effectuer sont les suivantes :

  1. Faire un clic-droite sur MyLibrary et choisir Build Path puis Remove from Build Path
  2. Ensuite valider la pop-up qui s’ouvre en vérifiant que le choix “Also unlink the folder from the project” est bien coché

Le temps que Eclipse rebuild le projet et ca devrait être nickel !

Conclusion

Voila ! c’est la fin de ce tutoriel sur les projets library Android. Si vous avez encore des interrogations, n’hésitez pas à poser vos questions dans les commentaires, je ferais de mon mieux pour y répondre et sinon je vous conseille l’article plus complet disponible sur le site officiel Android (en anglais par contre) : A lire ici

Page optimized by WP Minify WordPress Plugin