0

Android에서 동적 자동 완성 텍스트보기를 만들었습니다. 그것은 다음과 같은 구성 요소를 가지고 있습니다.동적 자동 완성을 위해 perfromFilter에서 AsyncTask를 호출합니다.

  1. 내 사용자 정의 POJO가있는 ArrayAdapter.
  2. 어댑터 구현 가능 필터링 가능.
  3. 이 필터는 가져 오는 문자 또는 제약 조건을 기반으로 모든 데이터를 가져 오는 AsyncTask를 호출합니다.
  4. 모든 데이터를 가져온 후에 AsyncTask는 데이터를 구문 분석 한 다음 목록을 필터로 반환하여 게시합니다.

시나리오는 : 나는 첫 번째 문자를 입력 한 후, AutoCompleteTextView에에 입력을 시작하면 는 지금, 그것은 비동기 호출을 시작합니다. 그런 다음 더 많은 문자를 입력하기 시작하면 각 문자에 대해 비동기를 다시 호출하고 필터를 통해 결과를 게시합니다.

문제 : 문제는 첫째 AsyncTask를이 첫 번째 문자에 대해 호출 될 때 나는 여전히 텍스트 뷰에 입력 해요 동안, 결과 목록의 AutoCompleteTextView에의 드롭 다운에 발표된다는 점이다. 그런 다음 각 문자가 비동기 적으로 실행될 때까지 많은 시간이 소요되는 최신 목록이 게시 될 때까지 기다려야합니다.

코드 : 다음은 사용중인 어댑터입니다.

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를 죽이고 있다고 생각합니다. 하지만 그렇게 할 수는 없습니다. 더 나은 해결책이 있거나 제 목표를 달성하는 방법을 제안하십시오.

문제를 이해하지 못했다면 알려주십시오. 그것 치명적인 것이 아니라 그 성가신 버그.

감사합니다.

FilterAsyncTask 실제로 유사합니다

+0

당신은 어떤 위치의 총 알 수 있습니까? –

+0

@SohailZahid : 항상 변화하므로 Mumbai를 타이핑하기 시작하면 먼저 M, MU, MUM 등으로 시작하는 모든 장소를 가져옵니다. 총 장소 수는 lacs 이상이므로이 접근법을 사용했습니다. –

답변

0

는 여기에 내가 어려운 방법을 배운 하나입니다. Filter이 있으면 AsyncTask이 필요하지 않습니다. 비 UI 배경 스레드 단지 doInBackground 같은 –에

  • performFiltering 실행됩니다.

  • publishResultsonPostExecute과 같이 performFiltering –을 완료 한 후에 UI 스레드에서 실행됩니다.

직접 performFilteringdoInBackground에서 논리를 넣어 코드를 재 작업. 이렇게하면 코드가 크게 단순 해지고 원하는 방식으로 작동하게됩니다.

+0

시도했습니다. 입력 된 첫 번째 문자의 목록과 드롭 다운의 최신 업데이트가 먼저 표시됩니다. –

+0

최소한'Filter'를 사용하면'performFiltering'이 실행되면 필터 요청을 대기열에 넣지 만 첫 번째 요청이 완료 될 때까지 실행하지 않으면 이전에 대기중인 요청이 모두 삭제됩니다. 간단한 해결책은 사용자가 특정 수의 문자를 입력 한 후에 만 ​​'필터'를 호출하는 것입니다. 더 복잡한 해결책은 사용자가 문자를 입력 할 때 타이머를 시작한 다음 만료 전에 다른 문자를 입력 할 때 타이머를 재설정하는 것입니다. 그런 다음 사용자가 특정 시간 동안 유휴 상태 일 때만 필터 요청을 시작합니다. –

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 work –