티스토리 뷰



이 자료들은 팁스소프트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하면 더 편리하게 볼수 있습니다.
* 알짜배기 프로그램 받기 - http://www.tipssoft.com/bulletin/tb.php/QnA/8406
* 관리자의 Tipssoft 이야기를 들어보세요 ( 트위터 ID : tipssoft )
* 안드로이드 강좌 목록 - http://www.tipssoft.com/bulletin/tb.php/old_bbs/501
현재 많이 사용되고 있는 몇몇 메신저 어플리케이션은 지금까지의 대화 내용을 대화창에 모두
보여주지 않고 대화창의 스크롤이 맨 위로 올라갔을때 일정 개수씩 추가하여 보여주고 있습니다.
이것은 이전의 대화내용을 사용자가 다시 봐야할 가능성이 적기 때문에 대화내용을 동적으로 관리하여
메모리의 사용을 최소화하기 위함입니다.
이번 강좌에서는 리스트뷰에서 사용할 수 있는 OnScrollListener 를 이용하여 데이터를 동적으로
추가하는 방법에 대하여 알아보도록 하겠습니다. 리스트뷰에 대하여 자세히 알고싶으신 분들은
아래의 강좌를 선행하여 숙지하시기 바랍니다.
리스트뷰 사용하기 - 기초편 : http://www.tipssoft.com/bulletin/tb.php/FAQ/918
리스트뷰 사용하기 - 활용편 : http://www.tipssoft.com/bulletin/tb.php/FAQ/921
1. OnScrollListener 에 대하여...
스크롤의 위치에 따라서 데이터를 추가하기 위해서는 먼저 OnScrollListener 를 구현하여 리스트뷰에
등록해야 합니다. OnScrollListener 에서 재정의해야할 함수는 아래와 같습니다.
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
public void onScrollStateChanged(AbsListView view, int scrollState)
onScroll 는 스크롤이 발생하는 동안 지속적으로 호출되는 메서드로 현재 보여지는 리스트뷰에서
상단에 보여지는 항목의 index 와 현재 리스트뷰에서 보여지는 항목의 수, 그리고 리스트뷰의 총
항목의 수를 알려줍니다.
onScrollStateChanged 는 현재 리스트뷰의 상태를 알려줍니다. scrollState 으로 넘어오는 상태값은
다음과 같은 3 가지입니다.
SCROLL_STATE_FLING ( 2 ) : 터치 후 손을 뗀 상태에서 아직 스크롤 되고 있는 상태입니다.
SCROLL_STATE_IDLE ( 0 ) : 스크롤이 종료되어 어떠한 애니메이션도 발생하지 않는 상태입니다.
SCROLL_STATE_TOUCH_SCROLL ( 1 ) : 스크린에 터치를 한 상태에서 스크롤하는 상태입니다.
onScroll 메서드의 경우 행위에 대한 콜백 메서드이고 onScrollStateChanged 메서드는 상태에 대한
콜백 메서드이기 때문에 재정의할 루틴의 성격에 따라서 어떤 메서드에서 코드를 구성할 것인지를
잘 선택해야합니다. onScrollStateChanged 메서드의 경우 한번 터치하여 스크롤 할 경우 최대
3 번 호출되지만 onScroll 메서드는 행위에 대한 콜백 메서드라는 특성상 100 번 이상 호출될 수도
있습니다. 아래의 그림은 두 메서드의 호출 빈도를 알아보기 위해 예제를 구성하여 한번의 스크롤로
각 메서드가 몇 번 호출됐는지를 나타내는 화면입니다.
onScroll 메서드에 사용자 재정의 루틴을 추가할 경우 높은 빈도로 해당 루틴이 수행되기 때문에
어플리케이션에 부하를 줄 수 있다는 단점이 있지만 사용자가 원하는 상황을 빨리 판단하여 매끄러운
처리를 할 수 있다는 장점이 있습니다.
반대로 onScrollStateChanged 메서드에 사용자 재정의 루틴을 추가하면 메서드의 호출 빈도가
상대적으로 낮기때문에 어플리케이션이 가볍게 동작할 수 있지만 상대적으로 매끄럽지 못하게
사용자 처리가 될 수 있다는 단점이 있습니다.
그러므로 OnScrollListener 를 사용할 때에는 두 메서드의 장단점을 잘 고려하여 사용해야합니다.
2. 동적 항목 추가 원리
리스트뷰의 항목을 동적으로 추가하려면 항목이 몇개씩 추가할 것인지와 항목을 추가할 기준 위치가
리스트뷰의 상단과 하단중 어느 지점인지를 정해야합니다. 이 강좌에서는 아래 그림처럼 리스트뷰의
최상단으로 스크롤됐을 때 ( 즉, 리스트뷰의 0 번 인덱스 항목이 보여졌을 때 ) 해당 항목 위로 10 개씩
데이터 항목이 추가되도록 예제를 구성할 것입니다.
3. 코드 구성 하기
간단하게 동적으로 항목을 추가하는 것에 대하여 OnScrollListener 인터페이스의 onScroll 메서드를
이용하는 방법과 onScrollStateChanged 메서드를 이용하는 방법을 각각 알아보도록 하겠습니다.
3.1 OnScrollListener 인터페이스의 onScroll 메서드를 사용하는 방법
onScroll 메서드는 호출 빈도가 매우 높기 때문에 스크롤이 보이지 않는다면 항목이 동적으로
추가되고 있다는 것을 느끼지 못할 정도로 매끄럽게 처리됩니다.
import android.app.Activity;
import android.os.Bundle;

import android.widget.AdapterView;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.view.View;
import java.util.ArrayList;
import android.widget.ArrayAdapter;

public class ListExActivity extends Activity implements OnScrollListener
{
// 동적으로 추가하는 데이터 단위
public final static int INSERT_COUNT = 10;
private ArrayAdapter<String> m_adapter = null;
private ListView m_list = null;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

String str;
ArrayList<String> str_list = new ArrayList<String>();
m_adapter = new ArrayAdapter(this, R.layout.list_item, str_list);

// 리스트뷰에 10개의 데이터를 추가한다.
for(int i = 0; i < INSERT_COUNT; i++) {
str = "리스트뷰 항목 - " + (i + 1);
m_adapter.insert(str, 0);
}

m_list = (ListView) findViewById(R.id.scroll_list);
m_list.setAdapter(m_adapter);
// 리스트뷰에 OnScrollListener 를 설정한다.
m_list.setOnScrollListener(this);
// 리스트뷰의 하단이 보여지도록 설정한다.
m_list.setSelection(m_list.getCount() - 1);
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
// 리스트뷰가 구성이 완료되어 보이는 경우
if(view.isShown()){
// 리스트뷰의 0 번 인덱스 항목이 리스트뷰의 상단에 보이고 있는 경우
if(firstVisibleItem == 0) {
// 항목을 추가한다.
String str;
for(int i = 0; i < INSERT_COUNT; i++) {
str = "리스트뷰 항목 - " + (totalItemCount + i + 1);
m_adapter.insert(str, 0);
}
// 0 번 인덱스 항목 위로 INSERT_COUNT 개수의 항목이 추가되었으므로
// 기존의 0 번 인덱스 항목은 INSERT_COUNT 번 인덱스가 되었다.
// 기존 0번 항목이 보여져서 항목이 추가될때 해당 항목의 모든 영역이
// 보이지않았을 수도 있으므로 이미 모든 영역이 노출됐던 INSERT_COUNT + 1
// 항목을 보이도록 설정하여 스크롤을 부드럽게 보이도록 한다.
view.setSelection(INSERT_COUNT + 1);
}
}
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState)
{
}
}
3.2 OnScrollListener 인터페이스의 onScrollStateChanged 메서드를 사용하는 방법
onScrollStateChanged 메서드는 호출 빈도가 onScroll 메서드에 비해 적고 사용가능한 상태값중
SCROLL_STATE_IDLE (스크롤 중지 상태) 에서만 항목 추가가 발생하므로 스크롤시 항목이
추가될 때마다 끊김 현상이 나타납니다.
import android.app.Activity;
import android.os.Bundle;

import android.widget.AdapterView;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.view.View;
import java.util.ArrayList;
import android.widget.ArrayAdapter;

public class ListExActivity extends Activity implements OnScrollListener
{
// 동적으로 추가하는 데이터 단위
public final static int INSERT_COUNT = 10;
private ArrayAdapter<String> m_adapter = null;
private ListView m_list = null;

private int m_list_count = 0;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

String str;
ArrayList<String> str_list = new ArrayList<String>();
m_adapter = new ArrayAdapter(this, R.layout.list_item, str_list);

// 리스트뷰에 10개의 데이터를 추가한다.
for(int i = 0; i < INSERT_COUNT; i++) {
str = "리스트뷰 항목 - " + (i + 1);
m_adapter.insert(str, 0);
}
m_list_count += INSERT_COUNT;

m_list = (ListView) findViewById(R.id.scroll_list);
m_list.setAdapter(m_adapter);
// 리스트뷰에 OnScrollListener 를 설정한다.
m_list.setOnScrollListener(this);
// 리스트뷰의 하단이 보여지도록 설정한다.
m_list.setSelection(m_list.getCount() - 1);
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState)
{
// 리스트뷰가 구성이 완료되어 보이는 경우
if(view.isShown()){
if(scrollState == SCROLL_STATE_IDLE) {
// 리스트뷰의 0 번 인덱스 항목이 리스트뷰의 상단에 보이고 있는 경우
if(view.getFirstVisiblePosition() == 0) {
// 항목을 추가한다.
String str;
for(int i = 0; i < INSERT_COUNT; i++) {
str = "리스트뷰 항목 - " + (m_list_count + i + 1);
m_adapter.insert(str, 0);
}
m_list_count += INSERT_COUNT;
// 0 번 인덱스 항목 위로 INSERT_COUNT 개수의 항목이 추가되었으므로
// 기존의 0 번 인덱스 항목은 INSERT_COUNT 번 인덱스가 되었다.
// 호출 빈도가 매우 적은 onScrollStateChanged 에서는 기존 0번 항목이 보여져서
// 항목이 추가될때 해당 항목의 모든 영역이 보였을 가능성이 크므로
// 해당 항목을 보이도록 설정한다.
view.setSelection(INSERT_COUNT);
}
}
}
}
}
4. 실행 화면


댓글