2012-07-25 45 views
4

我正在尋找一種替代方法來從android.net.Uri獲取查詢參數名稱。 getQueryParameterNames()需要api級別11.我想對任何較低級別的api執行相同的操作。 我在看getQuery(),它會返回'?'後的所有內容。標誌。最好的解決方法是解析該字符串並在'='之前搜索所有內容並捕獲它?我根本不知道每次會顯示哪些查詢參數。android.net.uri getQueryParameterNames()替代

+0

應該是一些簡單的字符串解析,給我有幾分鐘的時間,我會爲你提供一個函數 – Russ 2012-07-25 04:07:41

回答

12

唯一的問題與API的< 11是這種方法沒有實現設置結果到一個新的ArrayList,而不是鏈表。我想最好的想法是查看Android源代碼並使用API​​> = 11的實現。即使在較舊的API上,這也應該可以獲得絕對的功能。

這一個是從4.1.1,修改,以開放的作爲參數,所以你可以使用它了:如果你想深入到它自己

/** 
* 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); 
} 

,這裏是原來的代碼:

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

+0

我對此代碼感到困惑,我懷疑這是因爲我正在使用更新版本的Android SDK(API 18)。查詢變量由uri.getEncodedQuery()填充,它基於我的測試 - 編碼所有&字符。作爲使用編碼字符串的結果,對indexOf()的調用總是返回-1,並且返回整個查詢字符串,就像它是參數名稱一樣。 – markproxy 2014-06-09 18:11:49

+0

這裏是[Android 4.4.2的實現](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/net/Uri。 java#Uri.getQueryParameterNames%28%29),它是一樣的。你可能使用'Uri.Builder.query(String)',即使用'&'和'='來編碼整個參數。你應該使用'Uri.Builder.appendQueryParameter(String,String)'來編碼參數名稱和值,但保持分隔符完好無損。當你打電話給Uri時。getEncodedQuery()',它返回帶有編碼參數名稱和值的查詢,但是'&'和'='完好無損。 – foxter 2014-06-09 23:20:10

1

好吧,這是我想到的。有沒有編譯或測試它因此在這裏沒有保證

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; 
} 

我寫了這個深夜,沒有測試它,所以你可能通過增加或減少1。此外,我可能已經忘記了一些調整的呼叫將其添加到List的確切語法。我想對其他人看到的任何錯誤發表評論,但這是它的一般要旨。我有一種感覺,我忘了;某處。

編輯:作爲建議如下

+1

ArrayList result = new LinkedList (); 不是最好的想法 – kzotin 2013-05-21 14:14:07

+0

@paiNie你是對的,我已經改變了我的答案,只是創建一個新的ArrayList而不是LinkList。 – Russ 2013-05-21 16:59:12

2

我foxter同意,最好的選擇是讓從最新的Android版本的代碼,並添加到您的代碼庫。每當我遇到這樣的問題時,我都會創建一個方法來抽象版本特性。它是這樣的:

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); 
    } 
} 
3

如果你有java.net.URI(或創建一個),你可以使用URLEncodedUtils.parse得到的參數和值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()); 
} 
+0

絕對是迄今爲止提出的所有解決方案中最乾淨的! – ToddH 2014-06-06 17:44:16

+1

注意:這是org.apache.http.client.utils.URLEncodedUtils,只是爲了澄清。 – markproxy 2014-06-09 18:20:22