안드로이드에 가장 많이 쓰이는 위젯(widget) 중 하나가 리스트뷰(ListView)이다.
스마트폰이라는 작은 화면에 많은 데이터를 보여주기 위한 방법 중 하나로 리스트뷰가 사용된다.
하지만 아무리 좋은 리스트뷰라도 한번에 많은 데이터를 몽땅 불러온다면, 로딩시간이 오래걸릴 수 밖에 없다.
그래서 일정한 갯수의 데이터를 정해놓고, 로딩하는 것이 효율적이다.
그러기 위해서는 리스트뷰가 맨 하단(ListView의 마지막 셀)에 스크롤(scroll) 되었을때가 언제인지를 캐치하여 그 다음 데이터를 불러오는것을 알아보도록 한다.
안드로이드 앱의 ListView에서 데이터 20개씩 페이징 하는 영상
우선 ListView와 Adapter에서 UI로 사용 할 xml을 먼저 정의한다.
* listview_paging.xml - 리스트뷰가 있는 메인 액티비티의 UI를 작성한다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<!--ListView 끝에서 다음 데이터 로딩중에 보여줄 프로그레스바-->
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
<!--ListView를 정의한다.-->
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/progressbar"
/>
</RelativeLayout>
* row_listview.xml - 리스트뷰의 아답터의 각 셀에 적용시킬 UI를 작성한다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<!--ListView의 각 셀에 데이터가 들어갈 텍스트 라벨-->
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#ffffff"
android:gravity="center"
android:text="test"
android:textColor="#000000"
android:textSize="20dp" />
</LinearLayout>
다음은 java 파일를 작성한다.
*ListViewAdapter.java - 리스트뷰에 연결할 리스트뷰 아답터 코드를 작성한다.
package com.studio572.listviewpaging;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
/**
* Created by Administrator on 2016-10-13.
*/
public class ListViewAdapter extends BaseAdapter {
private LayoutInflater inflate;
private ViewHolder viewHolder;
private List<String> list;
public ListViewAdapter(Context context, List<String> list){
// MainActivity 에서 데이터 리스트를 넘겨 받는다.
this.list = list;
this.inflate = LayoutInflater.from(context);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
if(convertView == null){
convertView = inflate.inflate(R.layout.row_listview,null);
viewHolder = new ViewHolder();
viewHolder.label = (TextView) convertView.findViewById(R.id.label);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder)convertView.getTag();
}
// 각 셀에 넘겨받은 텍스트 데이터를 넣는다.
viewHolder.label.setText( list.get(position) );
return convertView;
}
class ViewHolder{
public TextView label;
}
}
* MainActivity.java - 리스트뷰의 페이징을 적용하는 메인 액티비티.
package com.studio572.listviewpaging;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.ProgressBar;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener {
private ListView listView; // 리스트뷰
private boolean lastItemVisibleFlag = false; // 리스트 스크롤이 마지막 셀(맨 바닥)로 이동했는지 체크할 변수
private List<String> list; // String 데이터를 담고있는 리스트
private ListViewAdapter adapter; // 리스트뷰의 아답터
private int page = 0; // 페이징변수. 초기 값은 0 이다.
private final int OFFSET = 20; // 한 페이지마다 로드할 데이터 갯수.
private ProgressBar progressBar; // 데이터 로딩중을 표시할 프로그레스바
private boolean mLockListView = false; // 데이터 불러올때 중복안되게 하기위한 변수
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_paging);
listView = (ListView) findViewById(R.id.listview);
progressBar = (ProgressBar) findViewById(R.id.progressbar);
list = new ArrayList<String>();
adapter = new ListViewAdapter(this, list);
listView.setAdapter(adapter);
progressBar.setVisibility(View.GONE);
listView.setOnScrollListener(this);
getItem();
}
@Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
// 1. OnScrollListener.SCROLL_STATE_IDLE : 스크롤이 이동하지 않을때의 이벤트(즉 스크롤이 멈추었을때).
// 2. lastItemVisibleFlag : 리스트뷰의 마지막 셀의 끝에 스크롤이 이동했을때.
// 3. mLockListView == false : 데이터 리스트에 다음 데이터를 불러오는 작업이 끝났을때.
// 1, 2, 3 모두가 true일때 다음 데이터를 불러온다.
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && lastItemVisibleFlag && mLockListView == false) {
// 화면이 바닦에 닿을때 처리
// 로딩중을 알리는 프로그레스바를 보인다.
progressBar.setVisibility(View.VISIBLE);
// 다음 데이터를 불러온다.
getItem();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// firstVisibleItem : 화면에 보이는 첫번째 리스트의 아이템 번호.
// visibleItemCount : 화면에 보이는 리스트 아이템의 갯수
// totalItemCount : 리스트 전체의 총 갯수
// 리스트의 갯수가 0개 이상이고, 화면에 보이는 맨 하단까지의 아이템 갯수가 총 갯수보다 크거나 같을때.. 즉 리스트의 끝일때. true
lastItemVisibleFlag = (totalItemCount > 0) && (firstVisibleItem + visibleItemCount >= totalItemCount);
}
private void getItem(){
// 리스트에 다음 데이터를 입력할 동안에 이 메소드가 또 호출되지 않도록 mLockListView 를 true로 설정한다.
mLockListView = true;
// 다음 20개의 데이터를 불러와서 리스트에 저장한다.
for(int i = 0; i < 20; i++){
String label = "Label " + ((page * OFFSET) + i);
list.add(label);
}
// 1초 뒤 프로그레스바를 감추고 데이터를 갱신하고, 중복 로딩 체크하는 Lock을 했던 mLockListView변수를 풀어준다.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
page++;
adapter.notifyDataSetChanged();
progressBar.setVisibility(View.GONE);
mLockListView = false;
}
},1000);
}
}
한번에 20개씩 보여주므로, 0부터 시작하여 20번째인 "Label 19"에서 프로그래스바로 로딩중임을 보여준다
'프로그래밍 > 안드로이드' 카테고리의 다른 글
[안드로이드] 쉐어드 프리퍼런스 저장/불러오기 (Shared Preference) (2) | 2017.08.13 |
---|---|
[안드로이드] xml selector - 버튼 눌림(클릭) 효과 커스텀하여 만들기 (1) | 2017.08.12 |
[안드로이드] AutoCompleteTextView 자동완성 검색 기능 구현 (0) | 2017.08.11 |
[안드로이드] 리스트뷰 검색 기능 구현 (android ListView search) (15) | 2017.08.10 |
[안드로이드] 커스텀 다이얼로그 ( Custom Dialog ) 만들기 (3) | 2017.08.09 |
댓글