티스토리 뷰



안드로이드/Android ArrayAdapter, BaseAdapter를 이용한 ListView 구현       


안드로이드 프로젝트를 진행하면서 ListView 를 이용한 화면 구성을 많이 하겠 됩니다. ListView란 Data를 List 형식으로 출력해주는 View 인데요. ArrayAdapter 와 BaseAdapter를 이용한 ListView 구현 방법에 대하여 알아 보겠습니다. Adapter란 ListView에 출력할 Data를 보관하는 장소라고 생각 하시면 되는데요. 실질적으로 List형식의 Data를 Adapter에 넘겨주면 Adapter가 ListView의 Row마다 List형식의 데이터를 출력 할 수 있게 도와 줍니다.


TesLlistViewActivity.java

public class TestListViewActivity extends Activity {
	
	private ArrayList mCareList = null;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        setLayout();
        
        mCareList = new ArrayList();
        
        for(int i = 0 ; i < 10 ; i++){
			mCareList.add(new InfoClass
					(
					i + "번째" + " ListView 입니다.", 
					getResources().getDrawable(R.drawable.ic_launcher), 
					"" + i
					));
		}
        
        // BaseAdapter 연결
        mListView.setAdapter(new CustomBaseAdapter(this, mCareList));
        
        // ArrayAdapter 연결
//        mListView.setAdapter(new CustomArrayAdapter(this, R.layout.list_row, mCareList));
        
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView arg0, View view, int position,
					long arg3) {
				
				Toast.makeText(
						getApplicationContext(), 
						"ITEM CLICK = " + position,
						Toast.LENGTH_SHORT
						).show();
			}
		});
    }
    
    private ListView mListView = null;
    
    private void setLayout(){
    	mListView = (ListView) findViewById(R.id.lv_list);
    }
}
//



CustomBaseAdapter.java ( 베이스어답터 )


public class CustomBaseAdapter extends BaseAdapter{
	
	private LayoutInflater inflater = null;
	private ArrayList infoList = null;
	private ViewHolder viewHolder = null;
	private Context mContext = null;
	
	public CustomBaseAdapter(Context c , ArrayList arrays){
		this.mContext = c;
		this.inflater = LayoutInflater.from(c);
		this.infoList = arrays;
	}

	// Adapter가 관리할 Data의 개수를 설정 합니다.
	@Override
	public int getCount() {
		return infoList.size();
	}

	// Adapter가 관리하는 Data의 Item 의 Position을 <객체> 형태로 얻어 옵니다.
	@Override
	public InfoClass getItem(int position) {
		return infoList.get(position);
	}

	// Adapter가 관리하는 Data의 Item 의 position 값의 ID 를 얻어 옵니다.
	@Override
	public long getItemId(int position) {
		return position;
	}

	// ListView의 뿌려질 한줄의 Row를 설정 합니다.
	@Override
	public View getView(int position, View convertview, ViewGroup parent) {
		
		View v = convertview;
		
		if(v == null){
			viewHolder = new ViewHolder();
			v = inflater.inflate(R.layout.list_row, null);
			viewHolder.tv_title = (TextView)v.findViewById(R.id.tv_title);
			viewHolder.iv_image = (ImageView)v.findViewById(R.id.iv_image);
			viewHolder.btn_button = (Button)v.findViewById(R.id.btn_button);
			viewHolder.cb_box = (CheckBox)v.findViewById(R.id.cb_box);

			v.setTag(viewHolder);
			
		}else {
			viewHolder = (ViewHolder)v.getTag();
		}
		
		viewHolder.tv_title.setText(getItem(position).title);
		
		// image 나 button 등에 Tag를 사용해서 position 을 부여해 준다. 
		// Tag란 View를 식별할 수 있게 바코드 처럼 Tag를 달아 주는 View의 기능
		// 이라고 생각 하시면 됩니다.
		viewHolder.iv_image.setTag(position);
		viewHolder.iv_image.setOnClickListener(buttonClickListener);
		
		viewHolder.btn_button.setTag(position);
		viewHolder.btn_button.setText(getItem(position).button);
		viewHolder.btn_button.setOnClickListener(buttonClickListener);
		
		viewHolder.cb_box.setTag(position);
		viewHolder.cb_box.setOnClickListener(buttonClickListener);
		
		return v;
	}
	
	// Adapter가 관리하는 Data List를 교체 한다. 
	// 교체 후 Adapter.notifyDataSetChanged() 메서드로 변경 사실을
	// Adapter에 알려 주어 ListView에 적용 되도록 한다.
	public void setArrayList(ArrayList arrays){
		this.infoList = arrays;
	}
	
	public ArrayList getArrayList(){
		return infoList;
	}
	
	private View.OnClickListener buttonClickListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			switch (v.getId()) {
			
			// 이미지 클릭
			case R.id.iv_image:
				Toast.makeText(
						mContext, 
						"이미지 Tag = " + v.getTag(),
						Toast.LENGTH_SHORT
						).show();
				break;
			
			// 버튼 클릭
			case R.id.btn_button:
				Toast.makeText(
						mContext, 
						"버튼 Tag = " + v.getTag(),
						Toast.LENGTH_SHORT
						).show();
				break;

			// CheckBox
			case R.id.cb_box:
				Toast.makeText(
						mContext, 
						"체크박스 Tag = " + v.getTag(),
						Toast.LENGTH_SHORT
						).show();
				break;

			default:
				break;
			}
		}
	};
	
	/*
	 * ViewHolder 
	 * getView의 속도 향상을 위해 쓴다.
	 * 한번의 findViewByID 로 재사용 하기 위해 viewHolder를 사용 한다.
	 */
	class ViewHolder{
		public TextView tv_title = null;
		public ImageView iv_image = null;
		public Button btn_button = null;
		public CheckBox cb_box = null;
		
	}
	
	@Override
	protected void finalize() throws Throwable {
		free();
		super.finalize();
	}
	
	private void free(){
		inflater = null;
		infoList = null;
		viewHolder = null;
		mContext = null;
	}
}
//



CustomArrayAdapter 

( 어레이어답터 )

ArrayAdapter는 생성시 Array를 넘겨주면 Super에서 자동으로 Data를 관리해 주므로 사용자 입장에서는 Adapter를 관리하기 편합니다.


public class CustomArrayAdapter extends ArrayAdapter{

	private ViewHolder viewHolder = null;
	private LayoutInflater inflater = null;
	private ArrayList infoList = null;
	private Context mContext = null;

	public CustomArrayAdapter(Context c, int textViewResourceId, 
			ArrayList arrays) {
		super(c, textViewResourceId, arrays);
		this.inflater = LayoutInflater.from(c);
		this.mContext = c;
	}

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

	@Override
	public InfoClass getItem(int position) {
		return super.getItem(position);
	}

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

	@Override
	public View getView(int position, View convertview, ViewGroup parent) {
		
		View v = convertview;
		
		if(v == null){
			viewHolder = new ViewHolder();
			v = inflater.inflate(R.layout.list_row, null);
			viewHolder.tv_title = (TextView)v.findViewById(R.id.tv_title);
			viewHolder.iv_image = (ImageView)v.findViewById(R.id.iv_image);
			viewHolder.btn_button = (Button)v.findViewById(R.id.btn_button);
			viewHolder.cb_box = (CheckBox)v.findViewById(R.id.cb_box);

			v.setTag(viewHolder);
			
		}else {
			viewHolder = (ViewHolder)v.getTag();
		}
		
		viewHolder.tv_title.setText(getItem(position).title);
		
		viewHolder.iv_image.setOnClickListener(buttonClickListener);
		viewHolder.iv_image.setTag(position);
		
		viewHolder.btn_button.setText(getItem(position).button);
		viewHolder.btn_button.setOnClickListener(buttonClickListener);
		viewHolder.btn_button.setTag(position);
		
		viewHolder.cb_box.setTag(position);
		viewHolder.cb_box.setOnClickListener(buttonClickListener);
		
		return v;
	}
//




 이렇게 해서 ArrayAdapter 까지 알아 봤구요. 한가지 주의 하셔야 할 점이 있습니다. 바로 ListView의 한 Row 안에 Button 이나 CheckBox가 들어가게 되는 경우 인데요. 이럴 경우에는 Button이나 CheckBox가 ListView의 Item(Row의 한행) 에 onItemClickListener 들어가는 이벤트를 먼저 가져 가버린 다는 점임니다. 그렇게 되면 아무리 ListView의 Item을 클릭해도 전혀 반응이 없게 되는 것이지요.



                         <  focusable = true 일 때 >             <  focusable = false 일 때 >


그래서 에 Button 과 Check 의 XML 속성에 "focusable = false" 를 해주시면, ListView의 Item이 이벤트를 받을 수 있기 때문에 정상 적으로 호출 하는 것을 보실 수 있습니다. 그리고 다른 방법은 Button 대신 ImageView 를 사용해 ClickEvent 를 달아서 사용 하는 경우입니다. ImageView는 원래 이벤트 속성이 없기 때문에 ListView의 Item에 이벤트를 가져갈 수 가 없습니다.

그외에 여러 방법들이 있을 수 있으며, 각각에 상황에 맞게 사용 하시면 될 거 같습니다.



파일첨부 :

TestListView.zip




스크린샷 :














댓글
  • 프로필사진 초보 좋은 정보 감사합니다.
    프로젝트에 많은 도움되었네요.
    2013.12.02 11:15
  • 프로필사진 권혁민 안녕하세요 포스트 잘보고있습니다 다름이 아니라요 아라비안 나이트님이 구현한 어레이 어댑터를 구현했는데요
    여기서 체크박스 클릭시 체크한 데이터항복을 리스트뷰에 뿌릴려고 하는데 어떻게 넘기는 코드를 구현을 못하겠네요..
    도와주세요 ㅠㅠ
    2014.02.05 10:16
  • 프로필사진 TravelerJ inflater.inflate(R.layout.list_row, null); 쓰면 동작 하기만 할 뿐 올바른 코드가 아닙니다
    inflater.inflate(R.layout.list_row, parent, false); 가 맞습니다

    이거 보고 따라하시는 분들 그대로 따라하지 마세요
    2015.09.02 23:30 신고
댓글쓰기 폼