Building sentences in the network news section of XING’s Android App
As you already know, the latest version of the XING Android App supports network news, which presents entries in the form of sentences in the phone’s language. This document explains how these sentences are built by David Montiel
The main idea we had for network news in the XING Android App was to emulate the platform’s behavior as it is quite robust and includes a lot of information and clickable content, as well as interaction options.
The simplified structure of each of the activities goes something like this: ACTOR performs a VERB with an OBJECT.
The most-common actors (entities which can trigger an activity) are things like XING users, companies, events, etc. Each of these can in turn perform a VERB, which includes things like “add as contact”, “join group”, “share”, etc. Finally there is a “recipient” of these verbs or objects, which can be groups, job ads, other XING users, links, etc.
As you can imagine, a large number of combinations are possible as XING users can join a group, post a job ad, recommend a link, etc. And to add some extra fun, it is possible for an item to have more than one actor as well as more than one object. So, for example, “David Montiel has joined the following groups: Group1, Group2 and Group3”, or something like “David Montiel and Juan Gomez have joined the Group1 group”.
Now this entry is about building the sentences in different languages, but we needed to explain the above information in order to introduce the kind of information we receive so sentences can be built.
The first step is obviously to have an activity object (Java Object) with a lot of information, such as the comments received by this activity, number of people who have “liked” it, whether it can be shared, liked, commented on, etc. But in order to build the sentence, we need to make sure the following information is present:
- List of actors
- Verb
- List of objects
Once we have this information, we can start building sentences. This process can be a bit complicated, but not very hard to understand. We have text resources with every possible combination (yes, one for each combination) of ACTOR, VERB and OBJECT.
The start of this process looks something like this:
public Spannable generateText(final Activity activity) { multiActors = 0; if (activity.actors.size() > 1) multiActors = (activity.actors.size() == 2) ? 1 : 2; switch (activity.verb) { case Activity.VERB_MAKE_FRIEND: return generateMakeFriend(activity); case Activity.VERB_JOIN: return generateJoin(activity); case Activity.VERB_POST: return generatePost(activity); …}
We have a multiActors flag which tells us if there is one, two, or more than two actors, which is helpful when building sentences such as:
- John Doe is now connected to Jane Doe. (one actor)
- John Doe and one other member are now connected to Jane Doe. (two actors)
- John Doe and X other members are now connected to Jane Doe. (more than two actors).
Let’s take the example of how we build the VERB_MAKE_FRIEND activity. In this case the used objects of the verb are also XING users.
The code to start generating this text is:
private Spannable generateMakeFriend(final Activity activity) { int text = 0; if (activity.actors.size() > 1) { text = R.string.format_make_friend_plural; if (activity.objects.size() > 1) { final int size = activity.objects.size(); if (size != 1) { if (size == 2) { text = R.string.format_make_friend_two_plural; } else if (size == 3) { text = R.string.format_make_friend_three_plural; } else { text = R.string.format_make_friend_more_plural; } } } } else { text = R.string.format_make_friend; if (activity.aggregated) { final int size = activity.objects.size(); if (size != 1) { if (size == 2) { text = R.string.format_make_friend_two; } else if (size == 3) { text = R.string.format_make_friend_three; } else { text = R.string.format_make_friend_more; } } } } return transform(service.getString(text), getTextAsArray(activity), getUserAsArray(activity), activity); }
As I explained earlier, this part is not that complicated, we just select a different text resource based on the number of actors and objects. So here are a couple of examples of the text resources we used in English for this case:
- format_make_friend = is now connected to {0}
- format_make_friend_two_plural = and {0} are now connected to {1} and {2}
As you can imagine, there is a lot going on in this part:
return transform(service.getString(text), getTextAsArray(activity), getUserAsArray(activity), activity);
This returns the text we want based on the information we have. We need to bear in mind that having a sentence is not all there is to it. If you’ve used the app you probably noticed that the names of people, groups, job ads, etc. are clickable, and clicking on them takes you to the correct place, in this case the person’s profile.
Here are the methods used to feed the transform method above
The first parameter is just the format string that we have in our text resources. This format will match the phone’s language, i.e.: “and {0} are now connected to {1}, {2} and {3}” for English and “und {0} haben folgende neue Kontakte: {1}, {2} und {3}” for German.
getTextAsArray returns an array with the text of the objects, in this case the names of the people.
private String[] getTextAsArray(Activity a) { final int size = a.objects.size(); final String[] s = new String[size]; for (int i = 0; i < size; i++) { s[i] = a.objects.get(i).text; } return s; }
getUserAsArray returns an array of URLs matching the elements of the above list and will be the place where the items of that array will land. For this we programmed the app to understand “com.xing.android:userId” URLs to take the user to the profile page of the person with that ID.
private String[] getUserAsArray(Activity a) { final int size = a.objects.size(); final String[] s = new String[size]; for (int i = 0; i < size; i++) { s[i] = "com.xing.android:" + a.objects.get(i).id; } return s; }
The transform method:
public Spannable transform(String s, String[] obj, String[] url, Activity activity) { … }
has a lot of code about insertion into the format string (the first parameter), text entries in the first array (second parameter), and making text entries clickable so that they will take the user to the URLs in the array which is the third parameter. That part will not be explained since it is an Android feature and beyond the scope of this text. But the first part of that method is interesting.
public Spannable transform(String s, String[] obj, String[] url, Activity activity) { if (multiActors != 0) { obj = insertPluralText(obj); url = insertMembersUrl(url, activity); } … }
This code supports the case where the activity has more than one actor and inserts them into the first element of the arrays, then inserts the text to be used into the texts array, and in the second array, the matching link where the user will be taken.
Here we add a format which says something like: “and one other person”, or “and other people” depending on the number of actors
private String[] insertPluralText(String[] linkedTexts) { String[] result = new String[linkedTexts.length + 1]; result[0] = (multiActors == 1) ? service .getString(R.string.one_more_user) : service .getString(R.string.more_members); for (int i = 1; i < linkedTexts.length + 1; i++) { result[i] = linkedTexts[i - 1]; } return result; }
insertMembersUrl method adds the URL where the user will be taken when clicking on the “and one other person”, or “other people” string. This is a link to a screen where we list the other members who participate in this activity.
private String[] insertMembersUrl(String[] urls, Activity activity) { String[] result = new String[urls.length + 1]; result[0] = getMultipleActorsUrl(activity); for (int i = 1; i < urls.length + 1; i++) { result[i] = urls[i - 1]; } return result; }
The last method uses a helping method, which basically creates a new URL with the form “com.xing.members:id1,id2,id3″ that we also programmed the app to understand and take the app user to a list of people based on the listed IDs.
private String getMultipleActorsUrl(Activity a) { final int size = a.actors.size(); final StringBuilder urlBuilder = new StringBuilder("com.xing.members:"); for (int i = 1; i < size; i++) { urlBuilder.append(a.actors.get(i).id + ","); } return urlBuilder.toString(); }
Now we have:
- The name of the first actor – John Doe
- The format string – and {0} are now connected to {1} and {2}
- Array of names to substitute – [“other people”, “Jane Doe”, “Markus Schmidt”]
- URLs where those texts will take us – ["com.xing.members:id1,id2,id3", "com.xing.android:id25", "com.xing.android:id30" ]
which we use to create an activity such as “John Doe and X other people are now connected to Jane Doe and Markus Schmidt”.
In the above example, all of the strings, i.e. “other people”, “Jane Doe” and “Markus Schmidt”, are clickable and take you to the correct part of the app.

David Montie is a Java/Android developer currently part of the Mobile team developing the Xing Android App.