I want to display recyclerview items after every 10 seconds. For instance, I have 8 items in my arraylist. Initially I want to display 3 items, then after waiting for 10 seconds first three visible items will disappear and next 3 items will show. how to achieve it ?
private void addList(){
ItemAdapter itemAdapter = new ItemAdapter();
itemAdapter.setImage(R.drawable.cachua);
itemAdapter.setText("Tomato");
mList.add(itemAdapter);
itemAdapter = new ItemAdapter();
itemAdapter.setImage(R.drawable.bo);
itemAdapter.setText("butter");
mList.add(itemAdapter);
itemAdapter = new ItemAdapter();
itemAdapter.setImage(R.drawable.cam);
itemAdapter.setText("oranges");
mList.add(itemAdapter);
mAdapter = new ListAdapter(mList, this);
mRecycleview.setAdapter(mAdapter);
mRecycleview.setLayoutManager(new LinearLayoutManager(this));
mAdapter.notifyDataSetChanged();
Log.d("anhtt","mlist : " +mList.size());
mList.clear();
itemAdapter = new ItemAdapter();
itemAdapter.setImage(R.drawable.quaxoai);
itemAdapter.setText("mango");
mList.add(itemAdapter);
itemAdapter = new ItemAdapter();
itemAdapter.setImage(R.drawable.dau);
itemAdapter.setText("strawberry");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mAdapter = new ListAdapter(mList, this);
mRecycleview.setAdapter(mAdapter);
mRecycleview.setLayoutManager(new LinearLayoutManager(this));
mAdapter.notifyDataSetChanged();
Log.d("anhtt","mlist : " +mList.size());
mList.add(itemAdapter);
itemAdapter = new ItemAdapter();
itemAdapter.setImage(R.drawable.tao);
itemAdapter.setText("Apple");
mList.add(itemAdapter);
mList.add(itemAdapter);
itemAdapter = new ItemAdapter();
itemAdapter.setImage(R.drawable.oi);
itemAdapter.setText("guava fruit");
mList.add(itemAdapter);
}
Interesting scenario. I think instead of adding time delays in adapter you should do that stuff in your class where you are passing data to adapter. Try to load first 3 items which you want to show then use handler to make delay of 10 seconds.
Like this :
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do your code to clear list and adding next 3 items and notify your adapter
}
}, 10000);
After this you need to clear your list and add next 3 items in list and notify your adapter that data has been updated. With this approach you can achieve your use case.
You should absolutely avoid using Thread.sleep() on the UI thread to keep it unblocked.
Blocking the UI thread will stop event dispatch (input, drawing events) and to a user the application appears to be frozen. If you end up blocking the UI thread for >5 seconds then the user will see an Application Not Responding dialog which makes for a very poor UX.
For your use-case you could use a Handler to dispatch events to the UI thread in a delayed manner
Here's a rough skeleton that might be resourceful:
public final class ScratchActivity extends AppCompatActivity {
private static final int INTERVAL_IN_MILLIS = 10000;
private static final int STEP = 3;
private Handler mHandler;
// Backing list of models to update the recycler view
private final List<Object> mItems = new ArrayList<>();
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler(Looper.getMainLooper());
/*
Set content view for activity etc.
Initialize recycler view, layout manager and adapter
*/
updateItems(0);
}
// Loop periodically to derive a sublist of items to update the recycler view adapter
private void updateItems(int index) {
if (index >= mItems.size()) return;
notifyRecyclerView(mItems.subList(index, Math.min(index + STEP, mItems.size())));
mHandler.postDelayed(() -> updateItems(index + STEP), INTERVAL_IN_MILLIS);
}
private void notifyRecyclerView(List<Object> data) {
// Replace data within the recycler view
}
}
Related
I'm using a RecyclerView in my Android project. I have a function, getPosts(int page) that adds new items to the relevant ArrayList. This is called in onLoadMore().
Now, when the activity starts, nothing happens. So I decided to call getPosts(1) manually from onCreate(). The problem with this is now page 1 is being loaded twice. Once by me in onCreate(), and for some reason again in onLoadMore(). Subsequent pages load perfectly.
So is there some way to tell the RecyclerView to start loading? If not, what should I do here?
Edit: As requested, here is a summary of my code:
private ArrayList<Post> postArrayList;
private RecyclerView recycler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_diary);
//...
postArrayList = new ArrayList<>();
recycler = ((RecyclerView) findViewById(R.id.recyclerDiary));
recycler.setHasFixedSize(true);
recycler.setLayoutManager(new LinearLayoutManager(this));
EndlessRecyclerViewScrollListener scrollListener = new EndlessRecyclerViewScrollListener(((LinearLayoutManager) recycler.getLayoutManager())){
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
Log.d("devlog", "Requesting page "+page+" from onLoadMore()");
getPosts(page);
}
};
recycler.setAdapter(new PostAdapter(postArrayList, new RecyclerViewClickHandler()));
recycler.addOnScrollListener(scrollListener);
Log.d("devlog", "Requesting page 1 from onCreate()");
getPosts(1);
}
//...
private void getPosts(int page){
int insertStartPos = postArrayList.size();
Post[] posts;
//get posts from the backend
for (int i = 0; i < posts.length(); i++){
postArrayList.add(posts[i]);
}
DiaryAdapter adap = ((DiaryAdapter) recycler.getAdapter());
if (insertStartPos == 0){
adap.notifyDataSetChanged();
} else {
adap.notifyItemRangeInserted(insertStartPos, bundleSize);
}
}
One way to avoid calling getNewItems(1) twice that means that you should have a global variable on your class, for example, named currentPage that is initialised with value 1 and is incremented every time you call getNewItems().
From now on call
getNewItems(currentPage);
currentPage++;
In my App I have crated a MyList.class which looks like this:
public class MyList {
private ArrayList<Obj> objList = new ArrayList<>();
//adds object to list
public void addObjToList(Obj obj) {
objList.add(obj);
}
//gets the whole list
public static ArrayList getObjList() {return objList;}
//gets the size of the list
public static int getObjListSize() {return objList.size();}
//removes obj from list based on his position
public void removeObj(int pos) {
objList.remove(pos);
}
}
From the CreateObj.class where I create the Obj I have this code to add it to the objList:
// creates the new object
Obj newObj = new Obj("Name", 3 /*int*/ );
// creates a new List
MyList myList = new MyList();
// adds the obj into the list
myList.addObjToList(newObj);
It successfully adds the obj to the list. Now from my Main_Activity.class I need to retrieve it and inflate it into a recyclerView, which I do in the onCreate() method like this:
currentObjList = MyList.getObjList();
//puts list into recycler
recyclerView = (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false));
adapter = new RecyclerAdapter(this, currentObjList);
recyclerView.setAdapter(adapter);
Notice that I do not set MyList myList = new MyList() in my Main_Activity because I want the list to be the one created in the CreateObj class.
Obviously this is not the right way to do it, because if, let's say I want to delete an element from the recyclerView, I need to remove it from the objList (in the MyList.class) too, and that's not possible since I cannot access the MyList.class methods without setting a new MyList(), and if I do set it to new, It would not keep the Obj added from the CreateObj class.
In short: How can I have the same objList to be both accessible and modifiable from both, CreateObj.class and Main_Activity.class.
Following my comment this is a draft of what I was suggesting.
Please note I haven't ran this code so it must have errors and typos, it is just to reflect the idea of what I was proposing.
The Activity that receives the input holds a referenct to the class that creates the object and to the class that holds the ArrayList.
Upon user input, the activity asks the object creator to create an ojbect and passes it back to the activity. Then the activity adds it to the list.
And finally it notifies the recycler adapter that the data has changed.
In MainActivity:
private CreateObj createObj;
private MyList myList;
//Other memeber variables for Input elements on the screen
//used in createObje.create() to build the new object.
public void onCreate(...){
...
createObj = new CreateObj();
myList = new MyList();
currentObjList = MyList.getObjList();
//puts list into recycler
recyclerView = (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false));
adapter = new RecyclerAdapter(this, currentObjList);
recyclerView.setAdapter(adapter);
...
aUserConfirmInputElement.setOnClickListener(new OnClickListener()){
public void onClick(){
Obj obj = createObj.create();
myList.addObjectToList(obj);
adapter.notifyDataSetChanged();
}
}
...
}
I intialize my recycler view adapter with an empty arraylist initially.
Then later once I fetch data from API I try to update the adapter by calling notifyDataSetChanged() but none of call back methods in my adapter is getting fired
void initRecyclerView()
{
myList = new ArrayList<>();
myRecyclerAdapter = new myRecyclerAdapter(getActivity(), myList, "");
myRecyclerView.setAdapter(myRecyclerAdapter);
linearLayoutManager = new LinearLayoutManager(getActivity());
myRecyclerView.setHasFixedSize(true);
myRecyclerView.setLayoutManager(linearLayoutManager);
}
After getting data from API I just update the adapter as follow :
void updateRecyclerView(ArrayList<Data> newList)
{
if (myList.isEmpty())
linearLayoutManager.removeAllViews();
myList.clear();
myList.addAll(newList);
myRecyclerAdapter.notifyDataSetChanged();
}
void updateRecyclerView(ArrayList<Data> newList)
{
//you don't have to removeviews
// if (myList.isEmpty())
// linearLayoutManager.removeAllViews();
myList.clear();
myList.addAll(newList);
myRecyclerAdapter.notifyDataSetChanged();
}
I made a costliest mistake and ponder around something else instead of looking it at different aspect.
I had SwipeRefreshLayout that wraps RecyclerView.
I should've just use setRefreshing(false) once data downloaded through API call. Instead I used setVisibility(VIEW.GONE) on mymSwipeRefreshLayout`.
This visibility change of SwipeRefreshLayout impacted RecyclerView within.
I hope none will do this mistake. Perhaps someone might come across this tiniest mistake so I Mark my answer as accepted answer.
First of all try to set layout manager and then set adapter to list :
void initRecyclerView()
{
linearLayoutManager = new LinearLayoutManager(getActivity());
myRecyclerView.setHasFixedSize(true);
myRecyclerView.setLayoutManager(linearLayoutManager);
myList = new ArrayList<>();
myRecyclerAdapter = new myRecyclerAdapter(getActivity(), myList, "");
myRecyclerView.setAdapter(myRecyclerAdapter);
}
Also pay attention that if you want to change data set or notify your adapter about the changes, you should do it in your main thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
myList.clear();
myList.addAll(newList);
myRecyclerAdapter.notifyDataSetChanged();
}
});
I wana create mobile application that uses RecyclerView with pagination that loads each time from dataBase 10 items, then when the list reaches the bottom I load 10 other items, so I used this metho to be notified if I reached the end of the list :
public boolean reachedEndOfList(int position) {
// can check if close or exactly at the end
return position == getItemCount() - 1;
}
and I used this function to load items :
#Override
public void onBindViewHolder(Info holder, int position, List<Object> payloads) {
if (reachedEndOfList(position)) {
Log.d("reachedEnd", "true");
this.autoCompletesTmp = getTmp();
notifyDataSetChanged();
}
}
getTmp() update the list of items with another 10 items, but i get this exception when I reached the bottom of the list:
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
I had the same problem a while ago:
This helped:
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
//Do something like notifyDataSetChanged()
}
};
handler.post(r);
List view is refreshed every N minutes of interval using a web service call. After refresh my current position goes back to the first item in list view.
Here is my code.
private void updateListUI(String response){
arrList = new ArrayList<Object>(); // to store array list
Object obj;
obj = some data; // some parsing of data and store in obj instance
arrList.add(obj);
if(listview.getAdapter()==null){
adapter = new customAdapter(myActivity,layout,arrList);
listview.setAdapter(adapter);
}else{
HeaderViewListAdapter adapterwrap =
(HeaderViewListAdapter) listview.getAdapter();
BaseAdapter basadapter = (BaseAdapter) adapterwrap.getWrappedAdapter();
customAdapter ad = (customAdapter)basadapter;
ad.setData(arrList); // it is a func in custom adapter that add items
ad.notifyDataSetChanged();
// here i want to set the position of list view,as it goes back to first item
}
}
BroadcastReceiver serviceReceiver = new BroadcastReceiver() {
public void onReceive( final Context context, final Intent intent ) {
updateListUI(intent.getStringExtra(response_from_service));
}
}
// Intent service calls webservice and broadcast response to receiver as finishes call. My question is on every updateListUI call list view goes back to first position. Is any way to solve this..?
use listLead.setSelectionFromTop(index, top); to set the position in list view
You can restore the posistion of your ListView using:
int position = 12; // your position in listview
ListView listView = (ListView) findViewById(R.id.listView);
listView.setSelectionFromTop(position, 0);
Instead of loading setAdapter during refresh
use the below code ... it will work
yourAdapterName.notifyDataSetChanged();
Just use the method notifyDataSetChanged() at the point where you want to refresh your list view.