0

我有一个问题,我知道问题出在哪里,但我不明白为什么它有时有效而有时无效。这就是我想做的。

我有一个显示 Google MapView 的 Android 应用程序,在此 MapView 之上有一个自动完成文本视图。我从 Google 获得值(以 json 格式),我可以在这个自动完成文本视图中显示它们。这一直有效。现在,当我按下从 Google 获得的选项之一时,我想放大到那个位置。这在大多数情况下都有效。

因此,当我按地址 Elfde 时,我会从 Google 收到 5 个选项/预测。之后我显示这些选项。其中一个选择是比利时的 Elfde-Liniestraat。Google MapView 会缩放到该位置。如果我键入不来梅,然后选择不来梅,德国它会缩放到该位置。但是当我输入 Peer 并选择 Peer, Belgium 时,我的 ArrayAdapter 中出现 indexOutOfBounds 异常。

现在代码:

当我的自动完成 TextView 中的文本更改时,我使用以下代码:

public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            if (count % 3 == 1){                    
                // Get the places and pass the argument in the TextView to the task.
                GetPlaces task = new GetPlaces();
                task.execute(_txtFindLocation.getText().toString());
            }
        }       

当我单击一个项目时,我使用此代码:

_txtFindLocation.setOnItemClickListener(new OnItemClickListener(){
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
            // Hide the keyboard.
            InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(_txtFindLocation.getWindowToken(), 0);

            Log.v("Take a look on variables", "item: " + String.valueOf(arg2) + ", AdapterView: " + arg0.getCount() + ", _strArrayAdapter: " + _strArrayAdapter.getCount());

            // Move to specified location.
            moveToLocation(arg0.getItemAtPosition(arg2).toString());

                    // Clear the adapter, to decrease the size.
            _strArrayAdapter.clear();
        }
    });

这是 indexOutOfBoundsException 发生的地方。对于比利时 Elfde-Liniestraat 的输入和选择:arg2 = 0,arg0.getCount() = 5,_strArrayAdapter(与 arg0 作为源链接)=5 对于德国不来梅的输入和选择:arg2 = 3, arg0.getCount() = 5, _strArrayAdapter = 5 对于比利时 Peer 的输入和选择(抛出错误的地方):arg2 = 0, arg0.getCount() = 0, _strArrayAdapter = 0

因此,这里肯定是引发错误的地方。_strArrayAdapter 在此函数中填充:

private class GetPlaces extends AsyncTask<String, Void, ArrayList<String>>{

    @Override
    protected ArrayList<String> doInBackground(String... params) {
        ArrayList<String> myPredictions = new ArrayList<String>();
        Log.d("Search places", "params: " + params[0].toString());
        try{
            URL myURL = new URL("https://maps.googleapis.com/maps/api/place/autocomplete/json?input="
                    + URLEncoder.encode(params[0], "UTF-8")
                    + "&types=geocode&language=en&sensor=true&key=API_KEY");
            URLConnection myURLConnection = myURL.openConnection();         
            BufferedReader myBufferReader = new BufferedReader(new InputStreamReader(myURLConnection.getInputStream()));

            String strLine;
            StringBuffer strBuffer = new StringBuffer();
            // Take Google's legible JSON and turn it into on big String.
            while((strLine = myBufferReader.readLine()) != null){
                strBuffer.append(strLine);
            }

            // Turn String into a JSON Object.
            JSONObject jsonPredictionsObject = new JSONObject(strBuffer.toString());
            // Get a JSON Array that is inside the JSON Object.
            JSONArray jsonPredictionsArray = new JSONArray(jsonPredictionsObject.getString("predictions"));

            for (int i = 0; i < jsonPredictionsArray.length(); i++){
                jsonPredictionsObject = (JSONObject) jsonPredictionsArray.get(i);
                myPredictions.add(jsonPredictionsObject.getString("description"));
            }
        }
        catch (IOException e){
            Log.e("Search places", "GetPlaces: doInBackGround", e);
        }
        catch (JSONException e){
            Log.e("Search places", "GetPlaces: doInBackGround", e);
        }

        return myPredictions;
    }

    protected void onPostExecute(ArrayList<String> result){
        Log.d("YourApp", "onPostExecute: " + result.size());

        // Update the adapter.
        _strArrayAdapter = new ArrayAdapter<String>(getBaseContext(), R.layout.activity_list_item);
        _strArrayAdapter.setNotifyOnChange(true);

        // Attach the adapter to the TextView.
        _txtFindLocation.setAdapter(_strArrayAdapter);

        for (String text : result){
            Log.d("Search places", "onPostExecute: result = " + text);

            _strArrayAdapter.add(text);
        }

            _strArrayAdapter.clear();

        Log.d("Search places", "onPostExecute: autoCompleteAdapter " + _strArrayAdapter.getCount());
    }

对于所有三个测试用例,最后一个 Log.d("Search places", "onPostExecute: autoCompleteAdapter " + _strArrayAdapter.getCount()); 给5个值!

所以 _strArrayAdapter 在所有情况下都会被填充,但是当我在某些情况下选择一个项目时,_strArrayAdapter 的值设置为 0,所以它没有被填充。

为什么会这样?

恕我直言,Martijn Haex

编辑感谢回复,我重新审视了我的代码(上面),现在它就像一个魅力。

4

2 回答 2

0

问题似乎出在您onTextChanged函数中的以下代码段中。顺便说一句,你为什么要在什么时候清除数组lengthOfModifiedText % 3 == 1?:

if (count % 3 == 1){
                _strArrayAdapter.clear();

当您输入 时"Peer",您的数组将被清除(没有元素)。每当您输入长度的文本时L, where L % 3 == 1,您strArrayAdapter将根据您的代码被清除。

于 2012-10-31T09:22:59.640 回答
0

当它们的字符数为 x*3+1 (1, 4, 7, 10, ...) 时,您似乎正在清除结果:

        if (count % 3 == 1){
            _strArrayAdapter.clear();

似乎您只想在拥有 3 个或更多字符时才搜索一个地方,对吧?那应该是

        if (count > 3){
            _strArrayAdapter.clear();

同样在 postExecute 中,我发现您在添加适配器的每个项目上都调用 notifyDataSetChanged() 。你可以稍微优化一下。事实上,你可以完全删除它:

protected void onPostExecute(ArrayList<String> result){
    Log.d("YourApp", "onPostExecute: " + result.size());

    // Update the adapter.
    _strArrayAdapter = new ArrayAdapter<String>(getBaseContext(), R.layout.activity_list_item);

    for (String text : result){
        Log.d("Search places", "onPostExecute: result = " + text);

        temp.add(text);
        _strArrayAdapter.add(text);
    }


    // Attach the adapter to the TextView.
    _txtFindLocation.setAdapter(_strArrayAdapter);

    Log.d("Search places", "onPostExecute: autoCompleteAdapter " + _strArrayAdapter.getCount());
}

此外,如果您遇到异常,请将堆栈跟踪放在帖子中,并在代码中对行号进行一些参考,以便更容易跟踪问题。

于 2012-10-31T09:44:56.320 回答