I am implementing nested RecyclerView
in my app, where a vertical Recycler holds another Recycler as its item. Everything is working fine I get the desired views. But I also need to add Sync Scrolling to these views. Which I have done so. The problem that I am facing is when the number of nested lists is only as big as 5-6 I get StackOverflowError
while scrolling. Here's what I followed in adding sync scrolling to my app.
I understand you get StackOverfloError
when there are too many nested RecyclerView
s, but what I don't get is how are even 5-6 RecyclerView
s too many. (I may need at sometime as many as 30 RecyclerView
s) but that is neither here nor there. However at any given time there are a maximum of 7 views displayed at any given time.
Here is my RecyclerView
layout file item_layout.xml
.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:visibility="visible">
<android.support.v7.widget.RecyclerView
android:id="@+id/programList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:visibility="gone"/>
<TextView
android:id="@+id/noEpgMessage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:textColor="#FFFFFF"
android:text="@string/no_epg_found"
android:gravity="left"
android:visibility="gone"/>
Within this RecyclerView
I have the following items in item.xml
.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="1dp">
<TextView
android:id="@+id/epgProgramItem"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textColor="#000000"
android:textSize="16sp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:gravity="center_vertical|left"
android:background="@drawable/epg_program_background"/>
Here is my Sync Scrolling code in ViewHolder.java
.
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
private int mLastY;
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
Log.d(TAG, "ProgramsList: onInterceptTouchEvent()");
if (rv.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
onTouchEvent(rv, e);
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
final int action = e.getAction();
if (action == MotionEvent.ACTION_DOWN) {
mLastY = rv.getScrollY();
Log.d("ListenerAddRemove", "Listener for " + rv.getTag() + " added");
rv.addOnScrollListener(selfRemovingListener);
}
else if (action == MotionEvent.ACTION_UP && rv.getScrollY() == mLastY) {
Log.d("ListenerAddRemove", "Removed");
rv.removeOnScrollListener(selfRemovingListener);
}
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
private final RecyclerView.OnScrollListener selfRemovingListener = new SelfRemovingOnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, 0);
scrollAll(recyclerView, dx, 0);
}
};
public void scrollAll(RecyclerView rv, int dx, int dy) {
Log.d(TAG, "Calling Recycler Tag : " + String.valueOf(rv.getTag()));
Log.d(TAG, "ScrollAll()");
for (int i = 0; i < ((recyclerList != null) ? recyclerList.size(): 0); i++) {
RecyclerView current = recyclerList.get(i);
if (current != rv) {
Log.d(TAG, "Current RecyclerView Tag : " + String.valueOf(current.getTag()));
current.scrollBy(dx, dy);
}
}
}
And my SelfRemovingOnScrollListener.java
.
public class SelfRemovingOnScrollListener extends RecyclerView.OnScrollListener {
@Override
public final void onScrollStateChanged(@NonNull final RecyclerView recyclerView, final int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
Log.d("ListenerAddRemove", "Self Removing Listener Removed");
recyclerView.removeOnScrollListener(this);
}
}
}
So here are my questions.
- How do I get around this i.e, if there is a way around it?
- Is there something else I can do to get the same functionality?
- How many
RecyclerView
s can I safely use with letting the application crash?
I've read the following link and it doesn't help me much.