I'm loading data from SQLite database in RecyclerView in batch of 25 records per load cycle. I figure out every thing but having problem with logic of calling data loading method in RecyclerView scroll listener.
Problem is list is loading nicely on scroll of recyclerView in emulator but when i tested in physical device, on Lenovo Phab 2 it worked fine but in Mi note 3, list doesn't load consistenly (sometime it loads, sometime not) more records on reaching bottom of scroll.
Below is the code I'm using in RecyclerView scrolle listener
private val RecyclerView_ScrollListener = object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView1: RecyclerView?, dx: Int, dy: Int) {
super.onScrolled(recyclerView1, dx, dy)
if (dy > 0) {
if (limit < rowCount_fromDatabase) {
visibleItemCount = layoutManager_MemberList.childCount
totalItemCount = layoutManager_MemberList.itemCount
firstVisibleItemPosition = layoutManager_MemberList.findFirstVisibleItemPosition()
if (visibleItemCount + firstVisibleItemPosition >= totalItemCount) {
limit += 25
load_Data()
}
}
}
}
I had the same problem. Try this
if (limit < returnedRowCount_fromDatabase) {
if((dy > 0) && (linearLayoutManager.findLastCompletelyVisibleItemPosition() == rowList.size() - 1)){
limit += 25;
load_Data();
}
}
I have written a class, that works with all types of LayoutManagers. It was tested on emulators and real devices.
It has blockers for preventing double loading of next page. When Listener.onListEndReached() returns true, it won't be called again, untill RecyclerViewOnScrollUpdater.loading will be set to false.
Also you can set visibleThreshold and enable/disable page loading via setting enabled.
What i use to scroll more is :
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (!recyclerView.canScrollVertically(1)){
//Load more data here. It will only trigger when you reach the end of your list and cannot scroll further
}
}
});
Hope this helps.
Related
I am trying to make my RecyclerView loop back to the start of my list.
I have searched all over the internet and have managed to detect when I have reached the end of my list, however I am unsure where to proceed from here.
This is what I am currently using to detect the end of the list (found here):
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ( (visibleItemCount+pastVisiblesItems) >= totalItemCount) {
loading = false;
Log.v("...", ""+visibleItemCount);
}
}
}
When scrolled to the end, I would like to views to be visible while the displaying data from the top of the list or when scrolled to the top of the list I would display data from the bottom of the list.
For example:
View1 View2 View3 View4 View5
View5 View1 View2 View3 View4
There is no way of making it infinite, but there is a way to make it look like infinite.
in your adapter override getCount() to return something big like Integer.MAX_VALUE:
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
in getItem() and getView() modulo divide (%) position by real item number:
#Override
public Fragment getItem(int position) {
int positionInList = position % fragmentList.size();
return fragmentList.get(positionInList);
}
at the end, set current item to something in the middle (or else, it would be endless only in downward direction).
// scroll to middle item
recyclerView.getLayoutManager().scrollToPosition(Integer.MAX_VALUE / 2);
The other solutions i found for this problem work well enough, but i think there might be some memory issues returning Integer.MAX_VALUE in getCount() method of recycler view.
To fix this, override getItemCount() method as below :
#Override
public int getItemCount() {
return itemList == null ? 0 : itemList.size() * 2;
}
Now wherever you are using the position to get the item from the list, use below
position % itemList.size()
Now add scrollListener to your recycler view
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstItemVisible = linearLayoutManager.findFirstVisibleItemPosition();
if (firstItemVisible != 0 && firstItemVisible % itemList.size() == 0) {
recyclerView.getLayoutManager().scrollToPosition(0);
}
}
});
Finally to start auto scrolling, call the method below
public void autoScroll() {
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
#Override
public void run() {
recyclerView.scrollBy(2, 0);
handler.postDelayed(this, 0);
}
};
handler.postDelayed(runnable, 0);
}
I have created a LoopingLayoutManager that fixes this issue.
It works without having to modify the adapter, which allows for greater flexibility and reusability.
It comes fully featured with support for:
Vertical and Horizontal Orientations
LTR and RTL
ReverseLayout for both orientations, as well as LTR, and RTL
Public functions for finding items and positions
Public functions for scrolling programmatically
Snap Helper support
Accessibility (TalkBack and Voice Access) support
And it is hosted on maven central, which means you just need to add it as a dependency in your build.gradle file:
dependencies {
implementation 'com.github.beksomega:loopinglayout:0.3.1'
}
and change your LinearLayoutManager to a LoopingLayoutManager.
It has a suite of 132 unit tests that make me confident it's stable, but if you find any bugs please put up an issue on the github!
I hope this helps!
In addition to solution above.
For endless recycler view in both sides you should add something like that:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val firstItemVisible = linearLayoutManager.findFirstVisibleItemPosition()
if (firstItemVisible != 1 && firstItemVisible % songs.size == 1) {
linearLayoutManager.scrollToPosition(1)
}
val firstCompletelyItemVisible = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
if (firstCompletelyItemVisible == 0) {
linearLayoutManager.scrollToPositionWithOffset(songs.size, 0)
}
}
})
And upgrade your getItemCount() method:
#Override
public int getItemCount() {
return itemList == null ? 0 : itemList.size() * 2 + 1;
}
It is work like unlimited down-scrolling, but in both directions. Glad to help!
Amended #afanit's solution to prevent the infinite scroll from momentarily halting when scrolling in the reverse direction (due to waiting for the 0th item to become completely visible, which allows the scrollable content to run out before scrollToPosition() is called):
val firstItemPosition = layoutManager.findFirstVisibleItemPosition()
if (firstItemPosition != 1 && firstItemPosition % items.size == 1) {
layoutManager.scrollToPosition(1)
} else if (firstItemPosition == 0) {
layoutManager.scrollToPositionWithOffset(items.size, -recyclerView.computeHorizontalScrollOffset())
}
Note the use of computeHorizontalScrollOffset() because my layout manager is horizontal.
Also, I found that the minimum return value from getItemCount() for this solution to work is items.size + 3. Items with position larger than this are never reached.
I was running into OOM issues with Glide and other APIs and created this Implementation using the Duplicate End Caps inspired by this post for an iOS build.
Might look intimidating but its literally just copying the RecyclerView class and updating two methods in your RecyclerView Adapter. All it is doing is that once it hits the end caps, it does a quick no-animation transition to either ends of the adapter's ViewHolders to allow continuous cycling transitions.
http://iosdevelopertips.com/user-interface/creating-circular-and-infinite-uiscrollviews.html
class CyclingRecyclerView(
context: Context,
attrs: AttributeSet?
) : RecyclerView(context, attrs) {
// --------------------- Instance Variables ------------------------
private val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
// The total number of items in our RecyclerView
val itemCount = adapter?.itemCount ?: 0
// Only continue if there are more than 1 item, otherwise, instantly return
if (itemCount <= 1) return
// Once the scroll state is idle, check what position we are in and scroll instantly without animation
if (newState == SCROLL_STATE_IDLE) {
// Get the current position
val pos = (layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
// If our current position is 0,
if (pos == 0) {
Log.d("AutoScrollingRV", "Current position is 0, moving to ${itemCount - 1} when item count is $itemCount")
scrollToPosition(itemCount - 2)
} else if (pos == itemCount - 1) {
Log.d("AutoScrollingRV", "Current position is ${itemCount - 1}, moving to 1 when item count is $itemCount")
scrollToPosition(1)
} else {
Log.d("AutoScrollingRV", "Curren position is $pos")
}
}
}
}
init {
addOnScrollListener(onScrollListener)
}
}
For the Adapter, just make sure to update 2 methods, in my case, viewModels is just my data structure that contains the data that I send over to my ViewHolders
override fun getItemCount(): Int = if (viewModels.size > 1) viewModels.size + 2 else viewModels.size
and on ViewHolder, you just retrieve the adjusted index's data
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val adjustedPos: Int =
if (viewModels.size > 1) {
when (position) {
0 -> viewModels.lastIndex
viewModels.size + 1 -> 0
else -> position - 1
}
} else {
position
}
holder.bind(viewModels[adjustedPos])
}
The previous implementation's hurt me haha, seemed way to hacky to just add a crazy amount of items, big problem when you run into Multiple cards with an Integer.MAX_VALUE nested RecyclerView. This approach fixed all the problems of OOM since it only necessarily creates 2 and ViewHolders.
Endless recyclerView in both sides
Add onScrollListener at your recyclerview
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstItemVisible = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
if (firstItemVisible != 1 && firstItemVisible % itemList.size() == 1) {
((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPosition(1);
}
int firstCompletelyItemVisible = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
if (firstCompletelyItemVisible == 0)
{}
if (firstItemVisible != RecyclerView.NO_POSITION
&& firstItemVisible== recyclerView.getAdapter().getItemCount()%itemList.size() - 1)
{
((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(itemList.size() + 1, 0);
}
}
});
In your adapter override the getItemCount method
#Override
public int getItemCount()
{
return itemList == null ? 0 : itemList.size() * 2 + 1;
}
I'm looking for best practices. I want to implement load more [progressbar] after every 10 items (Using RecyclerView).
In past, I did this by simply creating Loader class item and just added into the specific position in my List. Well, this time, I'm using PairList and it's impossible to add Loader class item (even tho I personally think, that's a pretty clean way to do it).
I found a few solutions on SO, which are almost the same: How to implement load more recyclerview in android
Is there any other way I could implement this load more progressbar after every 10th element (First load 10 items from API, then, when user reaches 10th item, we show progress bar [meanwhile we fetch the next 10 items], remove progress bar, add 10 items and so on).
Use this InfiniteScrollListener in your recycler scrollListener:
public abstract class InfiniteScrollListener extends RecyclerView.OnScrollListener {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager)recyclerView.getLayoutManager();
int visibleItemCount = linearLayoutManager.getChildCount();
int totalItemCount = linearLayoutManager.getItemCount();
int pastVisiblesItems = linearLayoutManager.findFirstVisibleItemPosition();
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loadMore();
}
}
}
protected abstract void loadMore();}
recyclerView Listener:
recyclerView.addOnScrollListener(new InfiniteScrollListener() {
#Override
protected void loadMore() {
boolean willLoad = //get your last api call data. if empty set false
int offset = recyclerView.getAdapter().getItemCount();
if(willLoad){
willLoad=false;
onCallApi(offset,10);
}
}
});
your api:
private void onCallApi(int offset,int limit){
//your api
}
Right now I have a Listview that stores 25 items, which are retrieved from an API. What I want is that the ListView refreshes on scroll up (retreive data from api call again). And add another 25 items on scroll down.
What could I use for this?
I found SwipeRefreshLayout, However, I can't find a way to distinguish scroll up and scroll down.
Use RecyclerView instead of ListVIew. Initialize the RecyclerView as follows :
RecyclerView Initialization :
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
videosAdapter = new VideosAdapter();
recyclerView.setItemAnimator(new SlideInUpAnimator());
recyclerView.setAdapter(videosAdapter);
// Pagination
recyclerView.addOnScrollListener(recyclerViewOnScrollListener);
Now setup OnScrollListener :
private RecyclerView.OnScrollListener recyclerViewOnScrollListener = new
RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
if (!isLoading && !isLastPage) {
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
&& firstVisibleItemPosition >= 0
&& totalItemCount >= PAGE_SIZE) {
loadMoreItems();
}
}
}
};
Once you get the response you need to add the received data to the list again.
I think your question is little bit misleading.If i am not wrong, here can be to thing.
Reload List on Over Scroll Down :- This functionality can be achieve by using SwipeRefreshLayout. Follow the android tutorial for Adding Swipe-to-Refresh To Your App.
Load more items on Over Scroll Up:- This is the part of Lay loading(Pagination) . If you are using ListViewthen you can use OnScrollListener and setFooterView() to make it done . Have a look at This thread.
Suggestion:- A simple suggestion Use RecyclerView instead of ListView to make better use of ViewHolder pattern.
I am using pixabay's api to show images in my recyclerview in grid layout.
Everything is working fine,i want to show images of next page in the same activity when user reaches end of images in recyclerview of first page i.e. when user reaches end of recyclerview make another request and increase page by 1 and show images of next page at the same time i want to keep images of first page as it is,if the user scrolls up again it should see images of first page.Here is my request.
https://pixabay.com/api/?q=yellow&key=MY_API_KEY&image_type=photo&page=1
How to automatically increase page no when user reaches end of recyclerview. I don't want to show buttons at the end of recyclerview for next page images
I think you'll need to implement addOnSrollListener() in your recyclerview.
You should implement something like that:
listRepositories.addOnScrollListener(new
RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int pastVisibleItems, visibleItemsCount, totalItemCount;
if (dy > 0) {
visibleItemsCount = layoutManager.getChildCount();
pastVisibleItems = layoutManager.findFirstVisibleItemPosition();
totalItemCount = layoutManager.getItemCount();
if ((visibleItemsCount + pastVisibleItems) >= totalItemCount) {
// method where you get your images
load(currentPage++);
}
}
}
});
I am trying to make my RecyclerView loop back to the start of my list.
I have searched all over the internet and have managed to detect when I have reached the end of my list, however I am unsure where to proceed from here.
This is what I am currently using to detect the end of the list (found here):
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ( (visibleItemCount+pastVisiblesItems) >= totalItemCount) {
loading = false;
Log.v("...", ""+visibleItemCount);
}
}
}
When scrolled to the end, I would like to views to be visible while the displaying data from the top of the list or when scrolled to the top of the list I would display data from the bottom of the list.
For example:
View1 View2 View3 View4 View5
View5 View1 View2 View3 View4
There is no way of making it infinite, but there is a way to make it look like infinite.
in your adapter override getCount() to return something big like Integer.MAX_VALUE:
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
in getItem() and getView() modulo divide (%) position by real item number:
#Override
public Fragment getItem(int position) {
int positionInList = position % fragmentList.size();
return fragmentList.get(positionInList);
}
at the end, set current item to something in the middle (or else, it would be endless only in downward direction).
// scroll to middle item
recyclerView.getLayoutManager().scrollToPosition(Integer.MAX_VALUE / 2);
The other solutions i found for this problem work well enough, but i think there might be some memory issues returning Integer.MAX_VALUE in getCount() method of recycler view.
To fix this, override getItemCount() method as below :
#Override
public int getItemCount() {
return itemList == null ? 0 : itemList.size() * 2;
}
Now wherever you are using the position to get the item from the list, use below
position % itemList.size()
Now add scrollListener to your recycler view
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstItemVisible = linearLayoutManager.findFirstVisibleItemPosition();
if (firstItemVisible != 0 && firstItemVisible % itemList.size() == 0) {
recyclerView.getLayoutManager().scrollToPosition(0);
}
}
});
Finally to start auto scrolling, call the method below
public void autoScroll() {
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
#Override
public void run() {
recyclerView.scrollBy(2, 0);
handler.postDelayed(this, 0);
}
};
handler.postDelayed(runnable, 0);
}
I have created a LoopingLayoutManager that fixes this issue.
It works without having to modify the adapter, which allows for greater flexibility and reusability.
It comes fully featured with support for:
Vertical and Horizontal Orientations
LTR and RTL
ReverseLayout for both orientations, as well as LTR, and RTL
Public functions for finding items and positions
Public functions for scrolling programmatically
Snap Helper support
Accessibility (TalkBack and Voice Access) support
And it is hosted on maven central, which means you just need to add it as a dependency in your build.gradle file:
dependencies {
implementation 'com.github.beksomega:loopinglayout:0.3.1'
}
and change your LinearLayoutManager to a LoopingLayoutManager.
It has a suite of 132 unit tests that make me confident it's stable, but if you find any bugs please put up an issue on the github!
I hope this helps!
In addition to solution above.
For endless recycler view in both sides you should add something like that:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val firstItemVisible = linearLayoutManager.findFirstVisibleItemPosition()
if (firstItemVisible != 1 && firstItemVisible % songs.size == 1) {
linearLayoutManager.scrollToPosition(1)
}
val firstCompletelyItemVisible = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
if (firstCompletelyItemVisible == 0) {
linearLayoutManager.scrollToPositionWithOffset(songs.size, 0)
}
}
})
And upgrade your getItemCount() method:
#Override
public int getItemCount() {
return itemList == null ? 0 : itemList.size() * 2 + 1;
}
It is work like unlimited down-scrolling, but in both directions. Glad to help!
Amended #afanit's solution to prevent the infinite scroll from momentarily halting when scrolling in the reverse direction (due to waiting for the 0th item to become completely visible, which allows the scrollable content to run out before scrollToPosition() is called):
val firstItemPosition = layoutManager.findFirstVisibleItemPosition()
if (firstItemPosition != 1 && firstItemPosition % items.size == 1) {
layoutManager.scrollToPosition(1)
} else if (firstItemPosition == 0) {
layoutManager.scrollToPositionWithOffset(items.size, -recyclerView.computeHorizontalScrollOffset())
}
Note the use of computeHorizontalScrollOffset() because my layout manager is horizontal.
Also, I found that the minimum return value from getItemCount() for this solution to work is items.size + 3. Items with position larger than this are never reached.
I was running into OOM issues with Glide and other APIs and created this Implementation using the Duplicate End Caps inspired by this post for an iOS build.
Might look intimidating but its literally just copying the RecyclerView class and updating two methods in your RecyclerView Adapter. All it is doing is that once it hits the end caps, it does a quick no-animation transition to either ends of the adapter's ViewHolders to allow continuous cycling transitions.
http://iosdevelopertips.com/user-interface/creating-circular-and-infinite-uiscrollviews.html
class CyclingRecyclerView(
context: Context,
attrs: AttributeSet?
) : RecyclerView(context, attrs) {
// --------------------- Instance Variables ------------------------
private val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
// The total number of items in our RecyclerView
val itemCount = adapter?.itemCount ?: 0
// Only continue if there are more than 1 item, otherwise, instantly return
if (itemCount <= 1) return
// Once the scroll state is idle, check what position we are in and scroll instantly without animation
if (newState == SCROLL_STATE_IDLE) {
// Get the current position
val pos = (layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
// If our current position is 0,
if (pos == 0) {
Log.d("AutoScrollingRV", "Current position is 0, moving to ${itemCount - 1} when item count is $itemCount")
scrollToPosition(itemCount - 2)
} else if (pos == itemCount - 1) {
Log.d("AutoScrollingRV", "Current position is ${itemCount - 1}, moving to 1 when item count is $itemCount")
scrollToPosition(1)
} else {
Log.d("AutoScrollingRV", "Curren position is $pos")
}
}
}
}
init {
addOnScrollListener(onScrollListener)
}
}
For the Adapter, just make sure to update 2 methods, in my case, viewModels is just my data structure that contains the data that I send over to my ViewHolders
override fun getItemCount(): Int = if (viewModels.size > 1) viewModels.size + 2 else viewModels.size
and on ViewHolder, you just retrieve the adjusted index's data
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val adjustedPos: Int =
if (viewModels.size > 1) {
when (position) {
0 -> viewModels.lastIndex
viewModels.size + 1 -> 0
else -> position - 1
}
} else {
position
}
holder.bind(viewModels[adjustedPos])
}
The previous implementation's hurt me haha, seemed way to hacky to just add a crazy amount of items, big problem when you run into Multiple cards with an Integer.MAX_VALUE nested RecyclerView. This approach fixed all the problems of OOM since it only necessarily creates 2 and ViewHolders.
Endless recyclerView in both sides
Add onScrollListener at your recyclerview
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstItemVisible = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
if (firstItemVisible != 1 && firstItemVisible % itemList.size() == 1) {
((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPosition(1);
}
int firstCompletelyItemVisible = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
if (firstCompletelyItemVisible == 0)
{}
if (firstItemVisible != RecyclerView.NO_POSITION
&& firstItemVisible== recyclerView.getAdapter().getItemCount()%itemList.size() - 1)
{
((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(itemList.size() + 1, 0);
}
}
});
In your adapter override the getItemCount method
#Override
public int getItemCount()
{
return itemList == null ? 0 : itemList.size() * 2 + 1;
}