Is there a callback for when RecyclerView has finished showing its items after I've set it with an adapter?
I've found a way to solve this (thanks to user pskink), by using the callback of LayoutManager
:
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
@Override
public void onLayoutChildren(final Recycler recycler, final State state) {
super.onLayoutChildren(recycler, state);
//TODO if the items are filtered, considered hiding the fast scroller here
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
if (firstVisibleItemPosition != 0) {
// this avoids trying to handle un-needed calls
if (firstVisibleItemPosition == -1)
//not initialized, or no items shown, so hide fast-scroller
mFastScroller.setVisibility(View.GONE);
return;
}
final int lastVisibleItemPosition = findLastVisibleItemPosition();
int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
//if all items are shown, hide the fast-scroller
mFastScroller.setVisibility(mAdapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
}
};
The good thing here is that it works well and will handle even keyboard being shown/hidden.
The bad thing is that it gets called on cases that aren't interesting (meaning it has false positives), but it's not as often as scrolling events, so it's good enough for me.
EDIT: there is a better callback that was added later, which doesn't get called multiple times. Here's the new code instead of what I wrote above:
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
@Override
public void onLayoutCompleted(final State state) {
super.onLayoutCompleted(state);
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
final int lastVisibleItemPosition = findLastVisibleItemPosition();
int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
//if all items are shown, hide the fast-scroller
fastScroller.setVisibility(adapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
}
});
callback on first/last visible item changed in RecyclerView?
You can use a RecyclerView.OnScrollListener
to be notified any time the RecyclerView is scrolled, and you can use getChildAt()
with getChildViewHolder()
to retrieve the top/bottom views and their respective ViewHolders:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView top = findViewById(R.id.top);
final TextView bottom = findViewById(R.id.bottom);
final RecyclerView recycler = findViewById(R.id.recycler);
recycler.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recycler.setLayoutManager(new LinearLayoutManager(this));
recycler.setAdapter(new MyAdapter());
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
View firstChild = recycler.getChildAt(0);
MyViewHolder topHolder = (MyViewHolder) recycler.getChildViewHolder(firstChild);
top.setText("Topmost visible view: " + topHolder.value);
View lastChild = recycler.getChildAt(recycler.getChildCount() - 1);
MyViewHolder bottomHolder = (MyViewHolder) recycler.getChildViewHolder(lastChild);
bottom.setText("Bottommost visible view: " + bottomHolder.value);
}
});
}
Android recyclerview does not show any data
Your method is asynchronous, so the code in onResponse
runs in the future, after your getTaskData
method has already returned an empty list. You would need to modify your program flow to accommodate this.
Here is an example of how you could define your own custom callback to handle that, by setting up the RecyclerView empty at first and then adding the data once it arrives.
Step 1: define an interface somewhere (e.g. in the activity or retrofit request class)
interface OnTasksRetrieved {
void getResult(List<Task> result);
}
Step 2: change your getTasksData
method to take a callback implementing that interface instead of returning a list
public static void getTasksData(OnTasksRetrieved callback) {
//...
call.enqueue(new Callback<List<Task>>() {
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
// Call your callback once you have retrieved the data
callback.getResult(response.body());
}
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
}
});
// do not return anything
}
Step 3: when you start the async call in onCreate
, create an instance of the callback interface to pass to it to handle the result
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_animation);
parent_view = findViewById(android.R.id.content);
initComponent();
// start the async fetch here - it won't finish until
// later in the future, when it will call the callback code
// below to update the RecyclerView data
getTasksData(
new OnTasksRetrieved() {
@Override
public void getResult(List<Task> result) {
// The code in here runs much later in the future - the adapter
// will already have been set up, but will be empty.
myAdapter.setItems(result); // add this method to the adapter
}
}
);
}
You will need to modify the adapter so it doesn't take the List as an input, but instead has a setItems
method something like this, which will be called once the data is retrieved:
private List<Task> items = new ArrayList<>();
public AdapterTasks(Context context, int animation_type) {
ctx = context;
this.animation_type = animation_type;
}
public void setItems(List<Task> data) {
items.clear();
items.addAll(data);
notifyDataSetChanged();
}
Related Topics
Android Java - Joda Date Is Slow
App Not Setup: This App Is Still in Development Mode
Setexactandallowwhileidle - Is Not Exact as of Developer Reference
Navigation Drawer Item Background Colour for Selected Item
How to Display Long Messages in Logcat
How to Get the Size of a Folder on Sd Card in Android
How to Databind to Ontextchanged for an Edittext on Android
Using Gson with Proguard Enabled
How to Programmatically Trigger the Touch Event in Android
Google Sceneform - Is It Deprecated? Any Replacement
How to Change the Track Color of a Switchcompat
Difference Between Build.Gradle (Project) and Build.Gradle (Module)
Android: Adding Static Header to the Top of a Listactivity
Android Hello, Gallery Tutorial -- "R.Styleable Cannot Be Resolved"
Failure [Install_Failed_Invalid_Apk]