Guava Multimap demo

16 08 2015

The problem

Handling maps that store collection of items under each key is very common. The thing I have in mind is this:

Map<String, List<Integer>> playerScoresMap = new HashMap<String, List<Integer>>();

Let’s assume that it stores scores for players. The player name is the key, and the value is a list of points scored by the player in following rounds. The task is to add a new score for the player after the round.

Plain Java solution

The HashMap solution requires you to:

  1. check if the player key already exist in map
    1. if it does not exist – add the key and create new array with score
    2. if it exists, get its current score array
  2. add new score to the array
  3. store the array under the user key

Source code for it is:

private static void addToOldStyleMultimap(String playerName, int scoreToAdd) {
    List<Integer> scoresList = new ArrayList<Integer>();
    if(playerScoresMap.containsKey(playerName)){
        scoresList = playerScoresMap.get(playerName);
    }

    scoresList.add(scoreToAdd);
    playerScoresMap.put(playerName, scoresList);
}

Guava solution

Guava has dedicated type for maps of that kind. Java’s:

Map<String, List<Integer>> playerScoresMap = new HashMap<String, List<Integer>>();

is equal to Guava’s Multimap:

Multimap<String, Integer> playerScoresMultimap = HashMultimap.create();

The difference is noticable in adding scores use case. To add new score for the player just make a call:

private static void addToGuavaMultimap(String playerName, Integer scoreToAdd) {
    playerScoresMultimap.put(playerName, scoreToAdd);
}

Guava’s Multimap does all checks for you. If player key exists, it adds new score to its score array. If it does not exist, a new key with one element score array is added.

Guava Example

Calling addToGuavaMultimap in the following manner:

addToGuavaMultimap("Alan", 2);
addToGuavaMultimap("Alan", 4);
addToGuavaMultimap("Alan", 6);
addToGuavaMultimap("Paul", 87);
System.out.println("Guava multimap result: " + playerScoresMultimap);

results with output:

Guava multimap result: {Alan=[4, 2, 6], Paul=[87]}

Source code download

The source code for this post is on my github: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo





Android status bar notifications [complete tutorial with source code]

1 02 2014

Displaying status bar notification is a common way to unobtrusively inform user that something has happened (like new GMail message notification). In your app you can display it whenever you want. I will guide you how to do it from basics. This is how notifications are presented to the user:

Status bar notifications

Status bar notifications

Google’s documentation regarding the notifications is here.

Source Code

All the source code for this tutorial you can download here.

1. Create Basic notification

Notification consists of three obligatory parameters: title text, content text and small icon image. Here is the code that creates such notification:

private Notification createBasicNotification() {
	NotificationCompat.Builder builder = new Builder(getApplicationContext());
	Notification notification = builder
			.setSmallIcon(R.drawable.me)
			.setContentTitle(getString(R.string.notif_title))
			.setContentText(getString(R.string.notif_text))
			.build();

	return notification;
}

2. Display Basic Notification

After it is built, you can display it to the user with NotificationManager:

private void displayNotification(Notification notification) {
	NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
	notificationManager.notify(myNotificationId , notification);
}

Where myNotificationId is final int and is equal to 1:

private static final int myNotificationId = 1;

Thanks to this ID later you can refer to that notification and update its content  or hide it when you need it.

This is how the notification looks like right now:

notif_my_custom

3. Auto Hide notification after it is touched

As for now nothing happens when user touches notification. To make it disappear after touch add this clause to the builder:

setAutoCancel(true)

4. Start activity after notification is touched

The most common action after user selects notification is to open activity presenting the detailed data that caused notification to be issued. You have to assign PendingIntent to notification in order to do it:

private PendingIntent preparePendingIntent() {
	Intent intent = new Intent(getApplicationContext(), MainActivity.class);
	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

	PendingIntent pendingIntent = PendingIntent.getActivity(
			getApplicationContext(), 
			0, 
			intent, 
			PendingIntent.FLAG_UPDATE_CURRENT);
	return pendingIntent;
}

After that, you assign this intent to notification with the builder command:

.setContentIntent(notificationIntent)

Now you have a basic notification that can issue certain action. Further customization is optional and introduced in newer versions of Android. Since possibilities are quite big, it is worth to continue improving the notification.

5. Filling in remaining small notification fields

Here is the code to fill in the remaining fields of small notification (this should be called on bilder object):

.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.me))
.setContentInfo(getString(R.string.notif_contentInfo))
.setWhen(Calendar.getInstance().getTimeInMillis() + 1000*60+60)
.setVibrate(vibrationPattern)

In order to make vibrations work you need to define pattern (mine is quite sophisticated :P):

long[] vibrationPattern = {0, 200, 800, 200, 600, 200, 400, 200, 200, 200, 100, 200, 50, 200, 50, 200, 50, 200, 500, 200};

but it surely can be simplier:

// Start without a delay
// Vibrate for 100 milliseconds
// Sleep for 1000 milliseconds
long[] pattern = {0, 100, 1000};

and require an VIBRATE permission in android manifest

<uses-permission android:name="android.permission.VIBRATE"/>

6. Apply big style to the notification

What actually is the Big Style? It is the notification with list of String. This is so called InboxStyle, since it is mainy used by GMail to notify user of incoming list of messages. This is how it looks like:

Notice that most of the elements are the same, except the 7 – the details list. Remember that big style works only for android versions higher than or equal to 4.2.

So now – how to build this list? Just create the notificationas it is done until now, and apply style to the builder:

.setStyle(inboxStyle)

And the inboxStyle is built like this:

private InboxStyle prepareBigNotificationDetails() {
	NotificationCompat.InboxStyle result = new InboxStyle();
	result.setBigContentTitle(getString(R.string.notif_inboxStyleTitle));
	result.addLine(getString(R.string.notif_inboxStyle_line1));
	result.addLine(getString(R.string.notif_inboxStyle_line2));
	result.addLine(getString(R.string.notif_inboxStyle_line3));
	result.addLine(getString(R.string.notif_inboxStyle_line4));
	result.addLine(getString(R.string.notif_inboxStyle_line5));
	result.addLine(getString(R.string.notif_inboxStyle_line6));
	return result;
}

Now test it (remember that only android 4.2 or higher will handle such notification). The result is like this:

InboxStyle notification

InboxStyle notification

notice that fields displayed on small notification are not visible in this style.

7. Updating notification content

Notification updates are quite simple: just set the fields you want to change with notification builder and call NotificationManagers’ notify() method providing the ID that you assigned to the notification that you need to update. The notification will be updated accordingly.

Download the Source Code

All the source code for this tutorial you can download here.

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Android: Action listener on EditText change

8 09 2012

If business logic requires to trigger any kind of action right after the user changes text in EditText View, the TextWatcher listener can be used. Good example of use is filter, that updates when user provides filtering criteria.

Add textChanged listener to EditText:

myEditText.addTextChangedListener(onSearchFieldTextChanged);

Implement listener to perform desired actions:

TextWatcher onSearchFieldTextChanged = new TextWatcher(){
	public void afterTextChanged(Editable s) {
		//your business logic after text is changed
	}
	public void beforeTextChanged(CharSequence s, int start, int count, int after){
		//your business logic before text is changed
	}

	public void onTextChanged(CharSequence s, int start, int before, int count){
		//your business logic while text has changed
	}
};

Did I help you?
I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!








%d bloggers like this: