Reputation: 430
I'm looking for an alternative way to get the query parameter names from an android.net.Uri. getQueryParameterNames() require api level 11. I'd like to do the same for any lower level api. I was looking at getQuery() which will return everything after the '?' sign. Would the best way to go about this be to parse that string and search for everything before an '=' and capture that? I simply do not know what query parameters will be presented every time.
Upvotes: 6
Views: 8201
Reputation: 17762
If you have a java.net.URI
(or create one), you can use URLEncodedUtils.parse
to get the parameters and values as NameValuePair
:
Map<String, String> parameters = Maps.newHashMap();
List<NameValuePair> params = URLEncodedUtils.parse(uri, "UTF-8");
for (NameValuePair param : params) {
parameters.put(param.getName(), param.getValue());
}
Upvotes: 4
Reputation: 1844
Ok well here's what I've came up with. Haven't compiled or tested it so no guarantees here
ArrayList<String> getQueryParamNames(String input)
{
ArrayList<String> result = new ArrayList<String>();
//If its everything after the ? then up to the first = is the first parameter
int start = 0;
int end = input.indexOf("=");
if (end == -1) return null; //No parameters in string
while (end != -1)
{
result.Add(input.substring(start, end)); //May need to do end - 1 to remove the =
//Look for next parameter, again may need to add 1 to this result to get rid of the &
start = input.indexOf("&", end);
if (start == -1) //No more parameters
break;
//If you want to grab the values you can do so here by doing
//input.substring(end, start);
end = input.indexOf("=", start);
}
return result;
}
I wrote this late at night, without testing it, so you might have to adjust some of the calls by adding or subtracting 1. Also I may have forgotten the exact syntax for adding to a List
. I guess comment on any errors for others to see but this is the general gist of it. I have a feeling I forgot a ;
somewhere.
EDIT: Set result to a new ArrayList instead of LinkList as suggested below
Upvotes: 1
Reputation: 4634
I agree with foxter that the best choice is to get the code from the newest Android version and add to your codebase. Everytime I'm faced with issues like this, I create a method to abstract versions idiosyncrasies. It goes like this:
public class FWCompat {
public static boolean isFroyo_8_OrNewer() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
}
public static boolean isGingerbread_9_OrNewer() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
}
public static boolean isHoneycomb_11_OrNewer() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
public static boolean isHoneycomb_13_OrNewer() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2;
}
public static boolean isJellyBean_16_OrNewer() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
}
}
@SuppressLint("NewApi")
public class FWUriCompat {
public static Set<String> getQueryParameterNames(Uri uri) {
if (FWCompat.isHoneycomb_11_OrNewer()) {
return uri.getQueryParameterNames();
}
return FW_getQueryParameterNames(uri);
}
private static Set<String> FW_getQueryParameterNames(Uri uri) {
if (uri == null) {
throw new InvalidParameterException("Can't get parameter from a null Uri");
}
if (uri.isOpaque()) {
throw new UnsupportedOperationException("This isn't a hierarchical URI.");
}
String query = uri.getEncodedQuery();
if (query == null) {
return Collections.emptySet();
}
Set<String> names = new LinkedHashSet<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);
names.add(Uri.decode(name));
// Move start to end of name.
start = end + 1;
} while (start < query.length());
return Collections.unmodifiableSet(names);
}
}
Upvotes: 2
Reputation: 355
The only problem with APIs < 11 is that this method is not implemented. I guess the best idea is to look into Android source code and use implementation from API >= 11. This should get you absolutely identic functionality even on older APIs.
This one is from 4.1.1, modified to take Uri as a parameter, so you can use it right away:
/**
* Returns a set of the unique names of all query parameters. Iterating
* over the set will return the names in order of their first occurrence.
*
* @throws UnsupportedOperationException if this isn't a hierarchical URI
*
* @return a set of decoded names
*/
private Set<String> getQueryParameterNames(Uri uri) {
if (uri.isOpaque()) {
throw new UnsupportedOperationException("This isn't a hierarchical URI.");
}
String query = uri.getEncodedQuery();
if (query == null) {
return Collections.emptySet();
}
Set<String> names = new LinkedHashSet<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);
names.add(Uri.decode(name));
// Move start to end of name.
start = end + 1;
} while (start < query.length());
return Collections.unmodifiableSet(names);
}
If you want to dig into it yourself, here is the original code:
Upvotes: 13