Get a map (dictionnary) of arguments->value from an URI in Android with any API Level requirements

If someone wants to use the URI class to parse an URL in Android, and get the given parameters the normal way to do it is :

String url = "http://www.example.com/?argument=value&argument2=value2&...";
Uri uri = Uri.parse(url);

//To get the value of known parameters
String argument = uri.getQueryParameter("argument");
String argument2 = uri.getQueryParameter("argument2");
...

//To look at all parameters if you don't know what you're waiting for
for (String key : uri.getQueryParameterNames()) {
   String value = uri.getQueryParameter(key);
   //Do something with value  key, like using a switch/case
}


The problem with the first method is that :

  • You need to know the arguments, and you cannot check if there is “unknow” arguments, like a malicious client trying to pass “include=X”
  • The query part of the URI is parsed each time you call setQueryParameter from the beginning !

The problem with the second method  is that :

  • When you call getQueryParameterNames() the whole query is parsed once
  • The query part of the URI is parsed each time you call setQueryParameter from the beginning !
  • getQueryParameterNames() is only available starting with Android 3.0 (API Level 11)

So I wrote the code below, which gives you a map of argument->value in one reading. You can then call any map-related function like containsKey(key) to know if an argument is in the URL, entrySet() to iterate through all argument/value, keySet() to get all the arguments, and values() to get all values. This only parse the URL once and is much more convenient. This code is in distributed in any GPL variant, take the one you prefer.

	/**
	 * Return a map of argument->value from a query in a URI
	 * @param uri The URI
	 */
	private Map<String,String> getQueryParameter(Uri uri) {
	    if (uri.isOpaque()) {
	    	return Collections.emptyMap();
	    }

	    String query = uri.getEncodedQuery();
	    if (query == null) {
	        return Collections.emptyMap();
	    }

	    Map<String,String> parameters = new LinkedHashMap<String,String>();
	    int start = 0;
	    do {
	        int next = query.indexOf('&', start);
	        int end = (next == -1) ? query.length() : next;

	        int separator = query.indexOf('=', start);
	        if (separator > end || separator == -1) {
	            separator = end;
	        }

	        String name = query.substring(start, separator);
	        String value;
	        if (separator < end)
	        	value = query.substring(separator + 1, end);
	        else
	        	value = "";
	        
	        parameters.put(Uri.decode(name),Uri.decode(value));

	        // Move start to end of name.
	        start = end + 1;
	    } while (start < query.length());

	    return Collections.unmodifiableMap(parameters);
	}