반응형

어댑터(Adapter)란?

 

Adapter는 하나의 Object(객체)로서, 보여지는 View와 그 View에 올릴 Data를 연결하는 일종의 Bridge다.

 

즉, 데이터의 원본을 받아 관리하고, 어댑터뷰가 출력할 수 있는 형태로 데이터를 제공하는 중간 객체 역할을 한다.

 

이러한 어댑터는 ArrayAdapter, CursorAdapter, SimpleAdapter 등등이 있다.

 

즉, 아래에서 어댑터 뷰에 대해 이야기를 하겠지만, 어댑터는 어댑터 뷰가 출력할 수 있는 데이터로 만들어 놓는 공간을 의미하고, 어댑터 뷰는 이 데이터를 출력하는 역할을 하게 된다.

 

이때 어댑터와 연결된 원본 데이터가 변경되면 notifyDataSetChanged 메서드를 호출하여 어댑터 뷰에 원본이 변경되었다고 알려주어 어댑터 뷰가 다시 그림을 그리도록 해야한다.

 

어댑터 뷰(Adapter View)란?

 

많은 정보를 효과적으로 처리하기 위해, View에 직접 정보를 주입하지 않고, Adapter라는 중간 매개체를 이용하기 때문에 붙여진 이름이다.

 

AdapterView는 ViewGroup을 상속받으므로, 내부적으로 많은 뷰들을 담을 수 있다.

 

대표적인 AdapterView의 서브 클래스로는 ListView, GridView, Spinner, Gallery 등등이 있다.

 

 

onChanged() 단계에서 각 view들이 자기자신을 requestLayout을 하면 listview는 자신의 자식이 붙어있는지를 확인 후 아이템의 수 만큼 getview를 호출되게 된다.

 

notifydatasetInvalidate()도 notifydatasetChanged와 유사한 메서드다. 다만 , notifydatasetInvalidate를 하게 되면 child의 수가, 처음 data 설정한 갯수만 유지가 되고 추가되거나 삭제된건 반영이 안된다. ( 즉, item의 데이터가 변경된 것만을 보여주게끔하는 것 같다. )  

https://okky.kr/article/396324

 

어댑터 뷰 예제

 

이를 토대로 실제 어댑터 뷰를 제작해보자.

 

 

<< activity_main.xml >>

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/lv_comment_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</android.support.constraint.ConstraintLayout>

우선 메인 xml의 모습이다. ConstraintLayout 속에 ListVIew를 넣어둠으로써 어댑터 뷰로 사용할 리스트뷰를 정의해준다.

 

 

<< MainActivity.java >>

package com.example.adaptertest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView listView = findViewById(R.id.lv_comment_view);
    }

    class MyAdapter extends BaseAdapter {

    }
}

 메인 액티비티에서는 ListView listview = findViewById를 통해 리스트뷰를 가리키도록 해주고

 

이제 이 리스트 뷰(어댑터 뷰)를 이용할 어댑터를 만들어야 하므로

 

어댑터 클래스인 MyAdapter을 하나 만들어준다.(이때 BaseAdapter을 상속하여 만들도록 한다.)

 

이때 MyAdapter 어댑터에서 어떤 데이터를 어댑터에서 이용할지 정해야 하므로 my_item.xml에서 데이터 양식을 만들어준다.

 

 

<< my_item.xml >>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ID : "
            android:textSize="30dp"/>
        <TextView
            android:id="@+id/tv_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="30dp"/>

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Phone : "
            android:textSize="30dp"/>
        <TextView
            android:id="@+id/tv_phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="30dp"/>

    </LinearLayout>
</LinearLayout>

my_item.xml에서는 간단하게 id, phone을 적을 수 있는 모델링을 xml로 나타내었다.

 

my_item.xml이 만들어졌으면 쌍으로 이루어지는 MyItem 클래스를 생성하여 inflate를 시켜줄 준비를 한다.

 

 

<< MyItem.java >>

package com.example.adaptertest;

public class MyItem {
    String id;
    String phone;

    public MyItem(String id, String phone) {
        this.id = id;
        this.phone = phone;
    }

    public MyItem() {}

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

해당 클래스는 item에 들어갈 항목인 id, phone를 가지며, get, set 함수를 기본적으로 정의해 두었다.

 

 

<< MyItemView.java >>

package com.example.adaptertest;

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;

// 뷰를 생성할 때는 필수 생성자가 2개이다.
public class MyItemView extends LinearLayout {
    TextView textView, textView2;

    public MyItemView(Context context) {
        super(context);
        init(context);
    }

    public MyItemView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_item, this, true);

        textView = findViewById(R.id.tv_id);
        textView2 = findViewById(R.id.tv_phone);
    }

    public void setId(String id){
        textView.setText(id);
    }
    public void setPhone(String phone){
        textView2.setText(phone);
    }
}

 

이제 MyItemView 클래스에서 인플레이션을 통해 메모리 객체화를 해야한다. LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
를 해주면 시스템 서비스를 통해 LayoutInflater를 가져다 쓴다고 정의해주고, 이를 캐스팅해서 받아준다.

 

그 뒤 inflate를 해주는데 my_item을 인플레이션 하고

현재 이 객체가 LinearLayout를 상속받았기에 최상위 레이아웃이 LinearLayout이니 this를 넣어준다.

 

<< MainActiviy.java >>

package com.example.adaptertest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView listView = findViewById(R.id.lv_comment_view);

        MyAdapter adapter = new MyAdapter();

        adapter.addItem(new MyItem("a","123"));
        adapter.addItem(new MyItem("bb","010-123"));
        adapter.addItem(new MyItem("ccc","010-123-234"));

        listView.setAdapter(adapter);
    }

    class MyAdapter extends BaseAdapter {
        private ArrayList<MyItem> items = new ArrayList<>();

        public void addItem(MyItem item){
            items.add(item);
        }

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

        @Override
        public MyItem getItem(int position) {
            return items.get(position);
        }

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

        @Override
        public View getView(final int position, final View convertView, ViewGroup parent) {
            MyItemView view = new MyItemView(getApplicationContext());

            MyItem item = items.get(position);
            view.setId(item.getId());
            view.setPhone(item.getPhone());

            return view;
        }
    }
}

이제 MyAdapter 클래스를 채울 수 있게 되었다.

어댑터에 들어갈 데이터는 ArrayList로 관리할 것이고, addItem, getCount, getItem, getItemId를 위와같이 설정해준다.

 

그리고 getView에서는 view를 담당하는 MyItemView를 통해 리스트뷰에 들어갈 각 데이터를 인플레이션하는 view를 선언해주고,

해당 item에 id, phone를 set해주고 난 후 마지막으로 view를 리턴해주면 리스트뷰에 하나의 데이터가 만들어지게 된다.

 


        MyAdapter adapter = new MyAdapter();

        adapter.addItem(new MyItem("a","123"));
        adapter.addItem(new MyItem("bb","010-123"));
        adapter.addItem(new MyItem("ccc","010-123-234"));

        listView.setAdapter(adapter);

 

최종적으로 위와 같이 어댑터를 생성하고, 어댑터에 데이터를 넣어주고, 리스트뷰에 만들어낸 어댑터를 연결시켜주면 아래와같은 최종 결과물이 나타나게 된다. 

 

반응형