0

我在Android中创建了一个动态的AutoCompleteTextView。它有以下组件。杀死AsyncTask在perfromFilter中调用动态AutoCompleteTextView

  1. ArrayAdapter与我自定义的POJO。
  2. 适配器实现可过滤。
  3. 此过滤器调用AsyncTask,该AsyncTask根据获取的字符或约束获取所有数据。
  4. 获取所有数据后,AsyncTask解析数据,然后将列表返回给过滤器进行发布。

方案: 现在,当我开始输入在AutoCompleteTextView,进入第一个字符后,它会启动异步调用。然后,当我开始输入更多字符时,它会再次为每个字符调用异步,并通过过滤器发布结果。

问题: 的问题是,当第一的AsyncTask被称为第一个字符,结果列表发表在降AutoCompleteTextView下来,而我还在原地在TextView中键入。然后,我必须等待最新的列表发布,这需要很长时间,因为每个字符都是异步执行的。

代码: 下面是我正在使用的适配器。

public class LocationAutoCompleteAdapter extends ArrayAdapter<LocationBean> implements Filterable { 

Context context; 
LayoutInflater inflater; 
ArrayList<LocationBean> list, tempList, suggestions; 

Filter nameFilter = new Filter() { 
    @Override 
    protected FilterResults performFiltering(CharSequence constraint) { 
     FilterResults filterResults = new FilterResults(); 
     if (constraint != null) { 
      try { 
       // Downloads location list 
       DownloadLocations exec = new DownloadLocations(); 
       String term = constraint.toString(); 
       Log.e(Constants.TAG, "CHARACTER: " + term); 
       if (exec.getStatus() == AsyncTask.Status.RUNNING) { 
        exec.cancel(true); 
       } else { 
        list = exec.execute(term).get(); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      filterResults.values = list; 
      filterResults.count = list.size(); 
     } 
     return filterResults; 
    } 

    @Override 
    protected void publishResults(CharSequence constraint, FilterResults results) { 

     List<LocationBean> filterList = (ArrayList<LocationBean>) results.values; 
     if (results != null && results.count > 0) { 
      clear(); 
      for (LocationBean locations : filterList) { 
       add(locations); 
       notifyDataSetChanged(); 
      } 
     } 
    } 
}; 

@Override 
public Filter getFilter() { 
    return nameFilter; 
} 

public LocationAutoCompleteAdapter(Context context) { 
    super(context, R.layout.location_autocomplete_list_item); 
    this.context = context; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    suggestions = new ArrayList<LocationBean>(); 
} 

public LocationAutoCompleteAdapter(Context context, ArrayList<LocationBean> list) { 
    super(context, R.layout.location_autocomplete_list_item, list); 
    this.context = context; 
    this.list = list; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    tempList = new ArrayList<LocationBean>(list); // this makes the difference. 
    suggestions = new ArrayList<LocationBean>(); 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    if (convertView == null) { 
     holder = new ViewHolder(); 

     convertView = inflater.inflate(R.layout.location_autocomplete_list_item, parent, false); 

     holder.name = (TextView) convertView.findViewById(R.id.autcom_name); 
     holder.state = (TextView) convertView.findViewById(R.id.autcom_state); 

     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    if (list.get(position).getState().isEmpty()) { 
     holder.state.setVisibility(View.GONE); 
    } else { 
     holder.state.setVisibility(View.VISIBLE); 
    } 
    holder.name.setText(list.get(position).getName()); 
    holder.state.setText(list.get(position).getState()); 

    return convertView; 
} 

class ViewHolder { 
    TextView name, state; 
} 

private class DownloadLocations extends AsyncTask<String, Void, ArrayList<LocationBean>> { 

    @Override 
    protected ArrayList<LocationBean> doInBackground(String... params) { 
     if (!isCancelled()) { 
      try { 
       //Create a new COUNTRY SEARCH url Ex "search.php?term=india" 
       URL url = new URL(Api.LOCATION_URL + params[0]); 

       HttpsURLConnection conn = Constants.getInitHttpsURLConnectionGET(url); 

       String locationResponse = Constants.getStringFromConnection(conn); 

       // INIT ArrayList 
       ArrayList locationList = new ArrayList<LocationBean>(); 
       locationList.clear(); 

       // PARSE RESPONSE 
       JSONObject locationResponseJsonObject = new JSONObject(locationResponse); 
       Log.e(Constants.TAG, "RESPONSE: " + locationResponseJsonObject); 

       JSONArray result = locationResponseJsonObject.getJSONArray(Constants.KEY_LOCATION_RESULTS); 

       for (int i = 0; i < result.length(); i++) { 
        JSONObject locationObject = result.getJSONObject(i); 

        String id = locationObject.getString(Constants.KEY_LOCATION_ID); 
        String state = locationObject.getString(Constants.KEY_LOCATION_STATE); 
        String name = locationObject.getString(Constants.KEY_LOCATION_NAME); 
        String district = locationObject.getString(Constants.KEY_LOCATION_TEXT); 

        locationList.add(new LocationBean(id, name, district, state)); 
       } 
       return locationList; 

      } catch (Exception e) { 
       Log.d("HUS", "EXCEPTION " + e); 
       return null; 
      } 
     } else { 
      return null; 
     } 
    } 
} 
} 

我的想法:我认为,杀死正在运行的AsyncTask它发布之前,其结果将是一个很好的解决方案。但我无法这样做。建议你是否有更好的解决方案,或者如何实现我的目标。

如果您不了解问题,请让我知道。它不是致命的,但它是一个烦人的bug。

谢谢。

+0

你知道总的位置没有? –

+0

@SohailZahid:它总是变化的,所以如果我开始打印孟买,首先它会获取所有以M开头的地方,然后是MU,然后是MUM等等。总人数超过了lacs,因此我使用了这种方法 –

回答

0

这里有一个我学到了艰辛的道路:

Filter实际上类似于AsyncTask。当您有Filter时,您不需要AsyncTask

  • performFiltering运行在非UI后台线程–就像doInBackground

  • publishResults只的performFiltering –就像onPostExecute完成后运行在UI线程。

返工你的代码,把你的逻辑从doInBackground直接进入performFiltering。这将大大简化您的代码,并使其以您想要的方式工作。

+0

试过了。它仍然首先显示输入的第一个字符的列表,然后显示下拉菜单中的最新更新。 –

+0

至少有'Filter',一旦'performFiltering'运行,它会排队过滤请求,但不会运行它们,直到第一个请求完成,同时任何先前排队的请求将被抛出。一个简单的解决方案是只有在用户输入了一定数量的字符后才调用“filter”。一个更复杂的解决方案是当用户键入一个字符时启动一个计时器,然后当用户在到期前键入另一个字符重置该计时器。然后,只有当用户空闲了一段时间后,才会启动过滤器请求。 –

0

每次开始搜索时,声明DownloadLocations对象为新鲜,尝试将DownloadLocations AsyncTask声明为全局变量。

public class LocationAutoCompleteAdapter extends ArrayAdapter<LocationBean> implements Filterable { 

Context context; 
LayoutInflater inflater; 
ArrayList<LocationBean> list, tempList, suggestions; 
DownloadLocations exec = new DownloadLocations(); 

Filter nameFilter = new Filter() { 
    @Override 
    protected FilterResults performFiltering(CharSequence constraint) { 
     FilterResults filterResults = new FilterResults(); 
     if (constraint != null) { 
      try { 
       // Downloads location list 
       String term = constraint.toString(); 
       Log.e(Constants.TAG, "CHARACTER: " + term); 
       if (exec.getStatus() == AsyncTask.Status.RUNNING) { 
        exec.cancel(true); 
       } else { 
        exec = new DownloadLocations(); 
        list = exec.execute(term).get(); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      filterResults.values = list; 
      filterResults.count = list.size(); 
     } 
     return filterResults; 
    } 

    @Override 
    protected void publishResults(CharSequence constraint, FilterResults results) { 

     List<LocationBean> filterList = (ArrayList<LocationBean>) results.values; 
     if (results != null && results.count > 0) { 
      clear(); 
      for (LocationBean locations : filterList) { 
       add(locations); 
      } 
      notifyDataSetChanged(); 
     } 
    } 
}; 

@Override 
public Filter getFilter() { 
    return nameFilter; 
} 

public LocationAutoCompleteAdapter(Context context) { 
    super(context, R.layout.location_autocomplete_list_item); 
    this.context = context; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    suggestions = new ArrayList<LocationBean>(); 
} 

public LocationAutoCompleteAdapter(Context context, ArrayList<LocationBean> list) { 
    super(context, R.layout.location_autocomplete_list_item, list); 
    this.context = context; 
    this.list = list; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    tempList = new ArrayList<LocationBean>(list); // this makes the difference. 
    suggestions = new ArrayList<LocationBean>(); 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    if (convertView == null) { 
     holder = new ViewHolder(); 

     convertView = inflater.inflate(R.layout.location_autocomplete_list_item, parent, false); 

     holder.name = (TextView) convertView.findViewById(R.id.autcom_name); 
     holder.state = (TextView) convertView.findViewById(R.id.autcom_state); 

     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    if (list.get(position).getState().isEmpty()) { 
     holder.state.setVisibility(View.GONE); 
    } else { 
     holder.state.setVisibility(View.VISIBLE); 
    } 
    holder.name.setText(list.get(position).getName()); 
    holder.state.setText(list.get(position).getState()); 

    return convertView; 
} 

class ViewHolder { 
    TextView name, state; 
} 

private class DownloadLocations extends AsyncTask<String, Void, ArrayList<LocationBean>> { 

    @Override 
    protected ArrayList<LocationBean> doInBackground(String... params) { 
     if (!isCancelled()) { 
      try { 
       //Create a new COUNTRY SEARCH url Ex "search.php?term=india" 
       URL url = new URL(Api.LOCATION_URL + params[0]); 

       HttpsURLConnection conn = Constants.getInitHttpsURLConnectionGET(url); 

       String locationResponse = Constants.getStringFromConnection(conn); 

       // INIT ArrayList 
       ArrayList locationList = new ArrayList<LocationBean>(); 
       locationList.clear(); 

       // PARSE RESPONSE 
       JSONObject locationResponseJsonObject = new JSONObject(locationResponse); 
       Log.e(Constants.TAG, "RESPONSE: " + locationResponseJsonObject); 

       JSONArray result = locationResponseJsonObject.getJSONArray(Constants.KEY_LOCATION_RESULTS); 

       for (int i = 0; i < result.length(); i++) { 
        JSONObject locationObject = result.getJSONObject(i); 

        String id = locationObject.getString(Constants.KEY_LOCATION_ID); 
        String state = locationObject.getString(Constants.KEY_LOCATION_STATE); 
        String name = locationObject.getString(Constants.KEY_LOCATION_NAME); 
        String district = locationObject.getString(Constants.KEY_LOCATION_TEXT); 

        locationList.add(new LocationBean(id, name, district, state)); 
       } 
       return locationList; 

      } catch (Exception e) { 
       Log.d("HUS", "EXCEPTION " + e); 
       return null; 
      } 
     } else { 
      return null; 
     } 
    } 
} 

}

+0

试过了。它只返回第一个字符的列表,没有其他的。 –

+0

检查我编辑的 –

+0

尝试.. .. dint工作 –