본문 바로가기
개발/android

ListView에 EditText를 넣을때 반드시 살펴봐야 할점

by 매몰 2017. 9. 11.

설정 페이지를 만들때 ListView로 EditText를 넣고 싶은 유혹에 빠진다

 

하지만 ListView의 특성상 사실 EditText는 적합하지 않다.

ListView는 각각의 row뷰를 재사용하여 메모리를 아끼기 때문에 

EditText의 변경값을 일일이 저장해 두었다가 다시 불려줘야 한다.

 

그리고 이때 진짜 주의할게 하나 있다.

변경 리스너의 중복을 방지하는 것이다. 반드시 재사용 뷰의 예전 리스너를 지워줘야 한다.

안그러면 예전 목록들과 뒤죽박죽 되버린다.

 

 

이해를 돕기 위해 리스너를 지우지 않았을때와 지웠을때도 비교해 보았다.

 

public class MainActivity extends Activity {

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

        //리스트 목록 넣기
        String[] names = getResources().getStringArray(R.array.list_item);
        ArrayList<Item> list = new ArrayList<>();

        int length = names.length;
        for (int i = 0 ; i < length ; i++)
            list.add(new Item(names[i]));

        ((ListView)findViewById(R.id.ItemListView)).setAdapter(new ItemAdapter(this, R.layout.list_row, list));
    }

    //리스트 목록 클래스
    private class Item {
        public String mName, mValue;
        public TextWatcher mTextWatcher;

        public Item(String name) {
            mName = name;
            mValue = "";

            //EditText 변경 리스너 생성
            mTextWatcher = new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    //변경된 값을 저장한다
                    mValue = s.toString();
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            };
        }
    }

    private class ItemAdapter extends ArrayAdapter<Item> {

        private int mResource;

        public ItemAdapter(Context context, int resource, List<Item> list) {
            super(context, resource, list);
            mResource = resource;
        }

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

            if (convertView == null) {
                itemView = new LinearLayout(getContext());

                LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                vi.inflate(mResource, itemView, true);
            }
            else
                itemView = (LinearLayout) convertView;

            Item item = getItem(position);
            
            ((TextView)itemView.findViewById(R.id.NameTextView)).setText(item.mName);
            
            EditText editText = (EditText)itemView.findViewById(R.id.ValueEditText);
            
            //예전 리스너를 삭제한다
            clearTextChangedListener(editText);
            
            //값을 불려오고 해당 리스너를 적용한다
            editText.setText(item.mValue);
            editText.addTextChangedListener(item.mTextWatcher);

            return itemView;
        }
        
        private void clearTextChangedListener(EditText editText) {
            //리스트 목록의 모든 리스너를 대상으로 검사하여 삭제해 준다
            int count = getCount();
            for (int i = 0 ; i < count ; i++)
                editText.removeTextChangedListener(getItem(i).mTextWatcher);
        }
    }
}

 

 

main.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="match_parent"
    android:gravity="center_vertical">

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

</LinearLayout>

 

 

list_row.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="match_parent"
    android:padding="10dp" android:gravity="center_vertical">

    <TextView android:id="@+id/NameTextView"
        android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"
        android:layout_marginRight="5dp"/>

    <EditText android:id="@+id/ValueEditText"
        android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/>

</LinearLayout>

 

 

array.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string-array name="list_item">
        <item>사자</item>
        <item>호랑이</item>
        <item>토끼</item>
        <item>코끼리</item>
        <item>강아지</item>
        <item>고양이</item>
        <item>표범</item>
        <item>송아지</item>
        <item>돼지</item>
        <item>코알라</item>
        <item>캥거루</item>
        <item>양</item>
        <item>염소</item>
        <item>늑대</item>
        <item>여우</item>
        <item>닭</item>
        <item>독수리</item>
        <item>쥐</item>
        <item>뱀</item>
        <item>말</item>
        <item>곰</item>
        <item>두더지</item>
        <item>사슴</item>
        <item>노루</item>
        <item>하마</item>
        <item>악어</item>
        <item>꿩</item>
        <item>비둘기</item>
        <item>까마귀</item>
        <item>고슴도치</item>
    </string-array>

</resources>

 

 

 

clearTextChangedListener() 함수를 주석처리 했을때 (예전 변경 리스너를 지워주지 않았을때)

 

 

 

 

 

clearTextChangedListener() 함수를 주석처리 하지 않았을때  (예전 변경 리스너를 지워주었을때)

 

 

 

 

도움이 되셨다면~ 정성으로 빚은 저희 앱!  많은 이용 바래요:)

 

https://meorimal.com/index.html?tab=spaceship

 

우주선 - 방치형 인공지능 투자 체험기

미리 맛보는 인공지능 투자!

(주)머리말 meorimal.com

 

https://meorimal.com/subway.html

 

지하철어디있니

더이상 고민하지 마세요. 뛸지 말지 딱 보면 알죠.

(주)머리말 meorimal.com

 

사업자 정보 표시
주식회사 머리말 | 고영진 | 서울특별시 송파구 중대로 135 서관 10층 (가락동, 아이티벤처타워) | 사업자 등록번호 : 524-88-00727 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2017-서울강남-03941호 | 사이버몰의 이용약관 바로가기