본문 바로가기
언어 공부/Android

[Android/JAVA] Adapter ..LayoutInflater.. ViewHolder 어렵다..

by 안다니. 2020. 9. 21.
반응형

안드로이드에서 Layout XML파일을 View객체로 만들기 위해 LayoutInflater를 이용한다.

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.my_layout, parent, false);

LayoutInflater.from()

  가장 자주 사용하는 방법으로,  LayoutInflater.from을 통해 LayoutInflater를 만드는 방법. 내부적으로 context#getSystemService를 호출 하고 있으며, 같은 context에서는 같은 객체를 리턴하기 때문에 굳이 멤버 변수로 선언해 놓지 않고 필요할 때마다 호출해 사용해도 괜찮다.

val inflater: LayoutInflater = LayoutInflater.from(context) 

 

1. 객체화 하고 싶은 xml 파일을 작성한다

2. 첫번째 예제 소스를 작성해, LayoutInflater 객체 사용


AddView를 이용한 ListView의 문제점

모든 item을 add할 때까지 다음 코드가 실행되지 않는다.

  • item이 적을 때는 add 코드가 금방 수행되지만, item이 많다면 성능상 문제가 생길 수 있다.
  • 모든 item을 한번에 다 그린다.
    • 사용자가 실제로 보게 되는 item의 갯수는 한정적일 수 있다. (스크롤을 끝까지 안할 수 있음)

 

  비동기적 접근이 불가능하기 때문에, Adapter를 사용한다.

Adapter를 사용하면 사용자 눈에 보이는 만큼만 미리 그려두었다가 사용자가 스크롤을 내리면 새로 받아오고 새로 받아오고 이러한 식으로 ListView를 보여주기 떄문에 문제점을 해결할 수 있다.

 

Adapter는 View와 View에 올릴 데이터 사이를 연결하는 하나의 다리(Bridge)라고 생각하면 된다.

 

Adapter

 

 

 

 

 

반응형

Adapter의 종류

BaseAdapter - 가장 기본이 되는 Adapter

ArrayAdapter - Array로 구성이 되어있는 Adapter, ArrayList<HashMap<String,String>>

CursorAdapter - 데이터베이스에 특화 되어있는 Adapter 

SimpleAdapter  - 한 항목에 문자열 데이터를 여러개 나열하는 경우, 

 


activity_main.xml

 

activity_main.xml

 

list_item_view.xml

list_item_view.xml

 

MainActivity.java

public class MainActivity extends AppCompatActivity {

    ArrayList<String> arrayList;
    ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView) findViewById(R.id.list_view);
        arrayList = new ArrayList<String>();

        arrayList.add("안");
        arrayList.add("녕");
        arrayList.add("하");
        arrayList.add("세");
        arrayList.add("요");

        MainAdapter myAdapter = new MainAdapter(MainActivity.this,arrayList);
        listView.setAdapter(myAdapter);
    }
}

 

 

 

반응형

 

 

 

MainAdapter.java

public class MainAdapter extends BaseAdapter {
    private LayoutInflater inflater;
    private ArrayList<String> item;
    ViewHolder viewHolder;

    public MainAdapter(Context context, ArrayList<String> item) {
        this.inflater = LayoutInflater.from(context);
        this.item = item;
    }

    @Override
    public int getCount() {
        return item.size();
    }

    @Override
    public Object getItem(int position) {
        return item.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view = convertView;

        if(view == null){
            viewHolder = new ViewHolder();
            view = inflater.inflate(R.layout.list_item_view,null);
            viewHolder.textView = view.findViewById(R.id.item_view_text);
            view.setTag(viewHolder);
        }else{
            viewHolder = (ViewHolder) view.getTag();
        }

        viewHolder.textView.setText(item.get(position));
        return view;
    }
}

 

ViewHolder.java

//View를 들고 있을 Class, 재사용 될 View를 저장하는 곳
//스크롤에 따라 데이터를 넣어주기 위함이다.
public class ViewHolder {
    public TextView textView = null;
}

 

실행결과

 

실행결과

 

 

 

ViewHolder?

 

'Holder'는 보관함이라는 뜻을 가지고 있는데요, 그렇다면 ViewHolder는 View를 담아두는 보관함이라는 뜻이 되겠네요.

View를 보관한다? 어떤 상황에서 사용하면 될까요?

 

화면에 한번에 7개의 아이템이 보이는 ListView가 있다고 가정하겠습니다. 최초에 화면에 보이는 7개의 View를 그리기 위해 getView()가 7번 실행되어 각각 View를 생성하여 반환하게 될 것입니다. 이 후에, 스크롤 하여 아래로 화면을 내려 8번째 아이템이 화면에 보이는 순간 다시 getView()가 실행되며 새로운 View를 생성하게 됩니다. 또 9번째, 10번째.. 새로운 아이템이 등장할 때마다 getView()에서는 새로운 View를 생성하게 됩니다.

 

일단, 언뜻 생각해도 굉장히 비효율적이라는 생각이 듭니다. 매번 새롭게 만들고 버리고..

사실 아이템을 구성하는 View가 간단하다면 별 차이가 없을 수도 있습니다. 화면을 내리는 순간, 순식간에 처리 할 테니까요. 하지만 반대로 하나하나의 View가 복잡하다면 어떨까요? ImageView에 TextView에 기타 등등.. 거기에 스크롤도 쭉쭉 내려버리면 ListView가 굉장히 바빠지겠군요!. 저희가 스크롤 중에 가끔 버벅이는 원인에 이러한 이유도 한 몫 한답니다. 실제로 findViewById()를 통해 위젯을 설정하는 작업은 메모리를 상당히 많이 사용하게 된다고 합니다.!

 

자, 여기까지 얘기를 듣고 눈치채신 분들도 있으시죠?

ViewHolder라는 건 결국, ListView의 일을 줄여 성능 향상에 그 목적이 있습니다. 위의 가정에서 최초 7개의 View에 대해서는 새로 만들지만, 이 후로 스크롤 시에 화면에서 사라지게 되는 맨 위의 View를 ViewHolder에 담아두었다가, 새로 보여지는 8번째 View를 만들 때는 새로 만들지 않고 ViewHolder에 담아두었던 View를 가져와 재사용 하게 됩니다. 그 다음 9번째 View를 생성 할 때는 2번째 View를, 10번째 View를 생성 할 때는 3번째 View를 ViewHolder에서 가져와 재사용 하게 되겠죠? ListView도 좀 수월해졌겠죠?

 

이전 ListView이해하기에서도 말씀드렸지만, 여기서 재사용이라 함은, View를 재사용 할 뿐이지, 데이터까지 재사용하지 않는다는 점. 꼭 명심하시길 바랍니다.

 

출처 : 

http://re-build.tistory.com/19

 

결론 : activity에서 ListView를 만들고, item들은 따로 xml을 만들어 준다. 그리고 이 두개를 연결해주는 게 바로 Adapter다. 라는 생각이 들었다

반응형

댓글