TonyCruze
TonyCruze

Reputation: 430

android.net.uri getQueryParameterNames() alternative

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

Answers (4)

Christopher Pickslay
Christopher Pickslay

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

Russ
Russ

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

Pedro Andrade
Pedro Andrade

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

foxter
foxter

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:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/net/Uri.java?av=f

Upvotes: 13

Related Questions