Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 806
TonyCruze Avatar asked Jul 25 '12 03:07

TonyCruze


People also ask

Why we use URI parse in android?

A Uri object is usually used to tell a ContentProvider what we want to access by reference. It is an immutable one-to-one mapping to a resource or data. The method Uri. parse creates a new Uri object from a properly formated String .

What is Uri fromParts?

Uri#fromParts() Creates an opaque Uri from the given components. Encodes the ssp which means this method cannot be used to create hierarchical URIs. When you call buildUpon() on this, the Builder contains the scheme, scheme-specific part (ssp) and the fragment (null in your case).

What is an android URI?

A URI is a uniform resource identifier while a URL is a uniform resource locator.


3 Answers

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

like image 52
foxter Avatar answered Sep 28 '22 09:09

foxter


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());
}
like image 30
Christopher Pickslay Avatar answered Sep 28 '22 08:09

Christopher Pickslay


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);
    }
}
like image 32
Pedro Andrade Avatar answered Sep 28 '22 07:09

Pedro Andrade