개발하는 두더지

[Android] RecyclerView + TMAP OpenAPI를 이용한 자동완성 검색창 만들기 본문

Java,Android

[Android] RecyclerView + TMAP OpenAPI를 이용한 자동완성 검색창 만들기

덜지 2017. 6. 26. 11:14

포스팅하게된 계기



짦은 개발 기간동안 스마트관광앱 공모전을 진행하면서 개발했던 것을 다시 정리하면서

공유하려고 올립니다.



개요

TMap, 카카오맵처럼 사용자가 가고싶은 곳을 검색하여 출발지 도착지를 지정하는 기능을 구현함.





그래서 간단하고 심플한 예제를 작성했습니다.

코드를 바로 보시려면 글 마지막 Github 링크로..





1글자부터 검색하려고하니 상당한 딜레이가 발생하여 2글자 이상부터 검색되도록 함.

(최적화를 해야하지만 일단 포스팅먼저...)




검색된 결과를 다른 Activity 또는 Fragment로 전달해줘야 하기때문에

Callback Interface를 만듬






RecyclerView란?


ListView는 초창기 UI를 수정할때마다 findViewById()를 호출했습니다. 상당한 무거운 작업이였기 때문에 이를 개선하고자 ViewHolder 패턴을 이용해 무거운 UI 작업을 피해왔습니다. ListView와 성능이 같지만 RecyclerView에서 ViewHolder 패턴을 강제하게 되었습니다.


RecyclerView에 대해서 개념을 더 이해하고 적고싶으면서 샘플을 적고싶지만 구글 가이드가 너무 잘되어있음.

https://developer.android.com/training/material/lists-cards.html?hl=ko#CardView



RecyclerView 위젯은 ListView의 더욱 향상되고 유연해진 버전입니다. 이 위젯은 한정된 수의 뷰를 유지함으로써 매우 효율적으로 스크롤할 수 있는 큰 데이터 집합을 표시하기 위한 컨테이너입니다. 사용자 작업 또는 네트워크 이벤트에 따라 런타임에 요소가 변경되는 데이터 컬렉션이 있는 경우RecyclerView 위젯을 사용하세요.

RecyclerView 클래스는 다음 기능을 제공하여 큰 데이터 집합의 표시 및 취급 작업을 단순화합니다.

  • 항목 위치지정을 위한 레이아웃 관리자
  • 항목 제거 및 추가와 같은 일반 항목 작업을 위한 기본 애니메이션

또한 필요에 따라 RecyclerView 위젯을 위한 사용자지정 레이아웃 관리자 및 애니메이션을 정의할 수도 있습니다.

그림 1RecyclerView 위젯.

RecyclerView 위젯을 사용하려면 어댑터와 레이아웃 관리자를 지정해야 합니다. 어댑터를 생성하려면 RecyclerView.Adapter 클래스를 확장하세요. 구현 세부사항은 데이터 집합의 사양 및 뷰 유형에 의해 결정됩니다. 자세한 내용은 아래의 를 참조하세요.

그림 2 - RecyclerView를 사용한 목록.

레이아웃 관리자는 항목 뷰를 RecyclerView 내에 배치하고 사용자에게 더 이상 보이지 않는 항목 뷰를 언제 재사용할지 결정합니다. 뷰를 재사용 (또는 재활용)하기 위해, 레이아웃 관리자는 어댑터에게 뷰의 콘텐츠를 데이터 집합의 다른 요소로 교체하도록 요청할 수 있습니다. 이런 방식으로 뷰를 재활용하면 불필요한 뷰 생성이나 리소스를 많이 소모하는 findViewById() 조회를 수행하지 않아도 되므로 성능이 개선됩니다.

RecyclerView는 다음과 같은 내장 레이아웃 관리자를 제공합니다.

사용자지정 레이아웃 관리자를 생성하려면 RecyclerView.LayoutManager 클래스를 확장하세요.

애니메이션

항목 추가 및 제거를 위한 애니메이션은 RecyclerView에서 기본적으로 활성화됩니다. 이러한 애니메이션을 사용자지정하려면 RecyclerView.ItemAnimator 클래스를 확장하고 RecyclerView.setItemAnimator() 메서드를 사용하세요.

다음 코드 예는 RecyclerView를 레이아웃에 추가하는 방법을 보여줍니다.

<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
   
android:id="@+id/my_recycler_view"
   
android:scrollbars="vertical"
   
android:layout_width="match_parent"
   
android:layout_height="match_parent"/>

RecyclerView 위젯을 레이아웃에 추가한 후, 객체 핸들을 얻어 레이아웃 관리자에 연결하고, 표시할 데이터의 어댑터를 첨부합니다.

public class MyActivity extends Activity {
   
private RecyclerView mRecyclerView;
   
private RecyclerView.Adapter mAdapter;
   
private RecyclerView.LayoutManager mLayoutManager;

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView
(R.layout.my_activity);
        mRecyclerView
= (RecyclerView) findViewById(R.id.my_recycler_view);

       
// use this setting to improve performance if you know that changes
       
// in content do not change the layout size of the RecyclerView
        mRecyclerView
.setHasFixedSize(true);

       
// use a linear layout manager
        mLayoutManager
= new LinearLayoutManager(this);
        mRecyclerView
.setLayoutManager(mLayoutManager);

       
// specify an adapter (see also next example)
        mAdapter
= new MyAdapter(myDataset);
        mRecyclerView
.setAdapter(mAdapter);
   
}
   
...
}

어댑터는 데이터 집합의 항목에 액세스할 수 있게 해주며, 항목 뷰를 생성하고, 원래의 항목이 더 이상 보이지 않을 경우 일부 뷰의 콘텐츠를 새 데이터 항목으로 교체합니다. 다음 코드 예는 TextView 위젯을 사용하여 표시된 문자열 배열로 이루어진 데이터 집합의 간단한 구현을 보여줍니다.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
   
private String[] mDataset;

   
// Provide a reference to the views for each data item
   
// Complex data items may need more than one view per item, and
   
// you provide access to all the views for a data item in a view holder
   
public static class ViewHolder extends RecyclerView.ViewHolder {
       
// each data item is just a string in this case
       
public TextView mTextView;
       
public ViewHolder(TextView v) {
           
super(v);
            mTextView
= v;
       
}
   
}

   
// Provide a suitable constructor (depends on the kind of dataset)
   
public MyAdapter(String[] myDataset) {
        mDataset
= myDataset;
   
}

   
// Create new views (invoked by the layout manager)
   
@Override
   
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   
int viewType) {
       
// create a new view
       
View v = LayoutInflater.from(parent.getContext())
                               
.inflate(R.layout.my_text_view, parent, false);
       
// set the view's size, margins, paddings and layout parameters
       
...
       
ViewHolder vh = new ViewHolder(v);
       
return vh;
   
}

   
// Replace the contents of a view (invoked by the layout manager)
   
@Override
   
public void onBindViewHolder(ViewHolder holder, int position) {
       
// - get element from your dataset at this position
       
// - replace the contents of the view with that element
        holder
.mTextView.setText(mDataset[position]);

   
}

   
// Return the size of your dataset (invoked by the layout manager)
   
@Override
   
public int getItemCount() {
       
return mDataset.length;
   
}
}






TMap 검색 API


TMap 연동해야하는 공모전이라 사용했지만 다른 OpenAPI를 사용해도 됨. 검색결과 파싱은 각자의 몫

https://developers.skplanetx.com/apidoc/pop-view/?guideDocId=11000041&lggId=KOR




검색할수있는 EditText 생성

기본 EditText를 이용하여 만들었습니다. 검색 키워드를 지우는 기능이 없기때문에 CustomEditText를 만들어서 구현해야합니다.

추후에 포스팅. 



RecyclerView 생성


위의 Sample의 기본 베이스는 같음.

 



Adpater 생성


위의 Sample의 기본 베이스는 같음.




filter 적용


검색 키워드를 입력하고 0.5후에 동작하는 스레드를 만들었습니다. 딜레이 없이 afterTextChanged가 호출되면 

속도가 상당히 느립니다. 별도의 스레드에서 동작되지만 마치 단일 스레드에서 동작하는 것 같이 끊김이 있다는 문제가 있었는데

StackOverflow에서 많은 사람들이 별점을 준 해결책을 적용했습니다.

filter의 기능은 TMap POI Rest API 에서 데이터를 받아오고 Adapter에 Set 해주는 기능입니다.




소스코드

https://github.com/pennya/SearchView


Comments