기존 프로젝트에서 RecyclerView를 통해 내용을 쭉 불러오고 있었는데

실험삼아 검색기준을 바꾸어 1000개정도의 아이템을 한번에 불러왔더니 

역시나 로딩이 오래걸리면서 앱이 버벅거렸다.


그래서 해결책을 찾던 중 페이징(맨 하단에 1,2,3.... 이런식으로 페이지번호를 이용한 기능)이 생각났지만

그것보다는 n개 씩 보여주는 대신 맨 끝으로 스크롤 되면 그다음(n+1 ~ 2n), 또 끝으로 스크롤되면 그다음(2n+1 ~ 3n) 을

불러오는 [새로고침 아이템 추가] 방식이 더 좋을것 같아서 찾아보았다.


찾아보던중 SwipeRefreshLayout 이라는 위젯을 발견하였는데 이와 비슷한 기능을 도와주었다.

하지만 내가 원하는 기능은 아니였다.


내가 원하는 기능은 밑에서 위로 스크롤하여 맨밑에 도달 하였을 때의 이벤트를 잡아야 하는데

해당 SwipeRefreshLayout는 위에서 밑으로 스크롤하여 맨 위에 도달 하였을 때 프로그레스가 생성되며

리플래시 리스너를 실행시켜주는 위젯이었다.

(쉽게 말하면 내가 원하는 기능은 페이스북처럼 밑에서 위로 스크롤 하면서 과거의 item들을 추가로 가져오는 기능)



내가 원하는 기능을 구현한 사이트를 겨우 찾았는데

https://www.youtube.com/watch?v=PqJAKA5IEF8


위의 동영상을 보면 알겠지만 맨위와 맨밑 새로고침을 전부 구현한 것이라

내 입맛대로 필요없는 부분(맨위 새로고침을 제외) 을 걸러내고 다시 만들어보았다.


///////////////////////////////////////////////////////////////////////////////



MainActivity.class

public class MainActivity extends AppCompatActivity implements AdapterItem.OnLoadMoreListener {

private AdapterItem mAdapter;
private ArrayList<Item> itemList;

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

itemList = new ArrayList<Item>();
RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.rvList);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new AdapterItem(this);
mAdapter.setLinearLayoutManager(mLayoutManager);
mAdapter.setRecyclerView(mRecyclerView);
mRecyclerView.setAdapter(mAdapter);


}

@Override
protected void onStart() {
super.onStart();
Log.d("MainActivity_", "onStart");
loadData();
}


//스크롤이 끝에 도달하였을 때 실행 내용
@Override
public void onLoadMore() {
Log.d("MainActivity_", "onLoadMore");
mAdapter.setProgressMore(true);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
itemList.clear();
mAdapter.setProgressMore(false);

///////이부분에을 자신의 프로젝트에 맞게 설정하면 됨
//다음 페이지? 내용을 불러오는 부분
int start = mAdapter.getItemCount();
int end = start + 15;
for (int i = start + 1; i <= end; i++) {
itemList.add(new Item("Item " + i));
}
//////////////////////////////////////////////////
mAdapter.addItemMore(itemList);
mAdapter.setMoreLoading(false);
}
}, 2000);
}

private void loadData() {
itemList.clear();
for (int i = 1; i <= 20; i++) {
itemList.add(new Item("Item " + i));
}
mAdapter.addAll(itemList);
}

}


AdapterItem.class

public class AdapterItem extends RecyclerView.Adapter<RecyclerView.ViewHolder>  {
private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;
private ArrayList<Item> itemList;

private OnLoadMoreListener onLoadMoreListener;
private LinearLayoutManager mLinearLayoutManager;

private boolean isMoreLoading = false;
private int visibleThreshold = 1;
int firstVisibleItem, visibleItemCount, totalItemCount, lastVisibleItem;

public interface OnLoadMoreListener{
void onLoadMore();
}

public AdapterItem(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener=onLoadMoreListener;
itemList =new ArrayList<>();
}

public void setLinearLayoutManager(LinearLayoutManager linearLayoutManager){
this.mLinearLayoutManager=linearLayoutManager;
}

public void setRecyclerView(RecyclerView mView){
mView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition();
Log.d("total", totalItemCount + "");
Log.d("visible", visibleItemCount + "");

Log.d("first", firstVisibleItem + "");
Log.d("last", lastVisibleItem + "");

if (!isMoreLoading && (totalItemCount - visibleItemCount)<= (firstVisibleItem + visibleThreshold)) {
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
isMoreLoading = true;
}
}
});
}

@Override
public int getItemViewType(int position) {
return itemList.get(position) != null ? VIEW_ITEM : VIEW_PROG;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_ITEM) {
return new StudentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false));
} else {
return new ProgressViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_progress, parent, false));
}

}

public void addAll(List<Item> lst){
itemList.clear();
itemList.addAll(lst);
notifyDataSetChanged();
}

public void addItemMore(List<Item> lst){
itemList.addAll(lst);
notifyItemRangeChanged(0,itemList.size());
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof StudentViewHolder) {
Item singleItem = (Item) itemList.get(position);
((StudentViewHolder) holder).tvItem.setText(singleItem.getItem());
}
}

public void setMoreLoading(boolean isMoreLoading) {
this.isMoreLoading=isMoreLoading;
}

@Override
public int getItemCount() {
return itemList.size();
}

public void setProgressMore(final boolean isProgress) {
if (isProgress) {
new Handler().post(new Runnable() {
@Override
public void run() {
itemList.add(null);
notifyItemInserted(itemList.size() - 1);
}
});
} else {
itemList.remove(itemList.size() - 1);
notifyItemRemoved(itemList.size());
}
}

static class StudentViewHolder extends RecyclerView.ViewHolder {
public TextView tvItem;

public StudentViewHolder(View v) {
super(v);
tvItem = (TextView) v.findViewById(R.id.tvItem);
}
}

static class ProgressViewHolder extends RecyclerView.ViewHolder {
public ProgressBar pBar;
public ProgressViewHolder(View v) {
super(v);
pBar = (ProgressBar) v.findViewById(R.id.pBar);
}
}
}


Item.class

public class Item  {

private String item;

public String getItem() {
return item;
}

public void setItem(String item) {
this.item = item;
}


public Item(String item) {
this.item=item;
}

}



activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:id="@+id/cl_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">


<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="400dp"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">


<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="TEST" />

</android.support.design.widget.CollapsingToolbarLayout>

</android.support.design.widget.AppBarLayout>

<android.support.v7.widget.RecyclerView
android:id="@+id/rvList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>

</android.support.design.widget.CoordinatorLayout>



item_progress.xml

<?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="wrap_content">

<ProgressBar
android:id="@+id/pBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"/>

</LinearLayout>



item_text.xml

<?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="wrap_content">

<TextView
android:id="@+id/tvItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"/>

</LinearLayout>



styles.xml

<resources>

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

<style name="NoTitle" parent="Theme.AppCompat.Light.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>


<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>





참고한 소스 : https://github.com/esantiago1/RecyclerViewEndlessScroll

+ Recent posts