RecyclerView android: Getting an item at a particular position - android

Is there any way to get an item of the RecyclerView at a particular position outside the adapter. e.g in ListView we could do:
listView.getItem(position);
Can we do this with RecyclerView ? and also is the order of provided data list maintained ?

You can add your own method to RecyclerView or I would suggest the RecyclerView.Adapter itself.
For instance, for ListView, you have:
#Override
public Object getItem(int position) {
return listData.get(position);
}
You can add the same thing to your RecylcerView.Adapter or access it another way by adding a simple method to your RecylcerView.Adapter:
public List<Model> getList() {
return this.mModel;
}
Use it like this:
recyclerView.getAdapter().getList().get(position)

Related

Recyclerview.notifyItemInserted() duplicates the list item

I have a requirement, where I should download the ad item while scrolling and update the list. Since calling notifyDatasetChnaged(), resets everything, I'm calling notifyItemInserted(position). But, calling this duplicated the items in the list. I found that there are no repeated items in the list. But after calling notifyItemInserted, it duplicates the item. I'm not getting how to resolve this issue. This what I'm doing:
mNewsList.add(mPreviousAdPosition, newsItem);
mAdapter.notifyItemInserted(mPreviousAdPosition);
If I call, it works properly, there are no repeated items. But I don't want my list items to recreate. What can be the issue ?
I had the same problem for exactly the same use case, the solution is:
Implement this method in your Adapter :
#Override
public long getItemId(int position) {
//Return the stable ID for the item at position
return items.get(position).getId();
}
Call this method in the Constructor of your Adapter :
//Indicates whether each item in the data set can be represented with a unique identifier
setHasStableIds(true);
You can add the object at the end of the array with each object having a position along with it where it needs to be shown in the recycler view. Sort this array on the basis of position before calling notifyItemInserted(position). In this way only required data will be drawn.I have recenlty followed this approach and works very well with dynamic sections added in between in recycler view.
You should add the item at the end of the list.
mNewsList.add(newsItem);
and then notify like this.
mAdapter.notifyItemInserted(mNewsList.size()-1);
Create a temporary list and add items as mentioned below:
List<YourModel> mTmpList = new ArrayList<YourMdel>();
//add items (from 0 -> mPreviousAdPosition) to mTmpList;
for(int i=0; i<mPreviousAdPosition; i++) {
mTmpList.add(mNewsList.get(i));
}
//add item at mPreviousAdPosition
mTmpList.add(newsItem);
//add remaining items and set i<=mNewsList.size() because we ha
for(int i=mPreviousAdPosition; i<=mNewsList.size(); i++) {
mTmpList.add(mNewsList.get(i - 1)); //because we have added item at mPreviousAdPosition;
}
mNewsList = mTmpList;
mAdapter.notifyDataSetChanged();
You code should be written like this:
public class RecyclerViewAdapter extends RecyclerView.Adapter{
...
public void addData(int position, Item newsItem) {
mNewsList.add(position, newsItem);
notifyItemInserted(position);
}
...
}
and then you need to call the fun addData

RecyclerView Adapter :OnBindViewHolder

Why do we use something like this to populate the recyclerview with data? Can't we just create a simple array of string like String[] titles and display them, like in ListView?
List< Information> data
public void onBindViewHolder(MyViewHolder holder, int position) {
Information current = data.get(position);
holder.title.setText(current.title);
holder.icon.setImageResource(current.iconId);
}
I recently watched a video on how to work with recyclerview and I can't understand why we have to create another class of information and then again create its array inside onBindViewHolder to show data.
Can anybody help me understand this code?
If you take a look at this example by google, they used an array dataset to populate data in RecyclerView.
Take a look at Google's docs:
Called by RecyclerView to display the data at the specified position. This method should update the contents of the itemView to reflect the item at the given position.
Note that unlike ListView, RecyclerView will not call this method again if the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined. For this reason, you should only use the position parameter while acquiring the related data item inside this method and should not keep a copy of it. If you need the position of an item later on (e.g. in a click listener), use getAdapterPosition() which will have the updated adapter position. Override onBindViewHolder(ViewHolder, int, List) instead if Adapter can handle effcient partial bind.
String [] title ;
int [] imageID;
onBindViewHolder(MyViewHolder holder, int position) {
Information current = data.get(position);
holder.title.setText(title [position]); holder.icon.setImageResource(imageID [position]);
}

Android add/replace Items within RecyclerView

I know there are lots of threads already on this topic, but none of the given solutions worked for me so far. I'm trying to add or update an item of a RecyclerView. Here's my code so far:
MainActivity
private MyListItemAdapter mAdapter;
private RecyclerView recyclerView;
// called on activity create
private void init() {
// initialize activity, load items, etc ...
mAdapter = new MyListItemAdapter(this, items);
recyclerView.setAdapter(mAdapter);
}
// called when I want to replace an item
private void updateItem(final Item newItem, final int pos) {
mAdapter.replaceItem(newItem, pos);
}
MyListItemAdapter
public class MyListItemAdapter extends RecyclerView.Adapter<MyListItemAdapter.MyListItemViewHolder> {
private List<Item> mItems;
public void replaceItem(final Item newItem, final int pos) {
mItems.remove(position);
mItems.add(position, newItem);
notifyItemChanged(position);
notifyDataSetChanged();
}
}
I tried to make this changes from the MainActivity aswell, but in every case I tried my list doesn't get updated. The only way it worked was when I reset the adapter to the recyclerView:
mAdapter.notifyDataSetChanged();
recyclerView.setAdapter(mAdapter);
which obviously is a bad idea. (aside from the bad side effects wouldn't even work when I'm using lazy loading on my lists).
So my question is, how can I make notifyDataSetChanged() work properly?
edit
I found a solution for replacing items. After mAdapter.replaceItem(newItem, pos); I had to call recyclerView.removeViewAt(position);
This works for replacing an item, but doesn't solve my problem when I want to add items (e.g. lazy loading) to my list
edit2
I found a working solution for adding items
Adapter:
public void addItem(final Item newItem) {
mItems.add(newItem);
notifyDataSetChanged();
}
Activity:
private void addItem(final Item newItem) {
mAdapter.addItem(newItem);
recyclerView.removeViewAt(0); // without this line nothing happens
}
For some reason this works (also: it doesn't remove the view at position 0), but I'm sure this isn't the correct way to add items to a recyclerView
This should work:
private ArrayList<Item> mItems;
public void replaceItem(final Item newItem, final int position) {
mItems.set(position, newItem);
notifyItemChanged(position);
}
ArrayList.set() is the way to go to replace items.
For adding items, just append them to mItems and then go notifyDatasetChanged(). Another way to go is to use notifyItemRangeInserted(). Depending on where/how are you adding new items and how many of them, it might be worth it.
Use
mItems.set(position, newItem);
instead of
mItems.add(position, newItem);
because .set method will replace your data to particular position.

Display new items at the top of a ListView

I'm using a list to populate a ListView (). The user is able to add items to the list. However, I need the items to be displayed at the top of the ListView. How do I insert an item at the beginning of my list in order to display it in reverse order?
By default list adds elements at bottom. That is why all new elements you add will show at bottom. If you want it in reverse order, may be before setting to listadapter/view reverse the list
Something like:
Collections.reverse(yourList);
Another solution without modifying the original list, override getItem() method in the Adapter
#Override
public Item getItem(int position) {
return super.getItem(getCount() - position - 1);
}
Updated: Example
public class ChatAdapter extends ArrayAdapter<ChatItem> {
public ChatAdapter(Context context, List<ChatItem> chats) {
super(context, R.layout.row_chat, chats);
}
#Override
public Item getItem(int position) {
return super.getItem(getCount() - position - 1);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = inflater.inflate(R.layout.row_chat, parent, false);
}
ChatItem chatItem = getItem(position);
//Other code here
return convertView;
}
}
You should probably use an ArrayAdapter and use the insert(T, int) method.
Ex:
ListView lv = new ListView(context);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, R.id...);
lv.setAdapter(adapter);
...
adapter.insert("Hello", 0);
The ListView displays the data as it is stored in your data source.
When you are adding in your database, it must be adding the elements in the end. So, when you are getting all the data via the Cursor object and assigning it to the ArrayAdapter, it is in that order only. You should basically be trying to put data in the beginning of the database, rather that in the end, by having some time-stamp maybe.
Using ArrayList, you can do it by Collections.reverse(arrayList) or if you are using SQLite, you can use order by.
You can add element at the beginning of the list: like
arraylist.add(0, object)
then it will always display the new element at the top.
mBlogList is a recycler view...
mBlogList=(RecyclerView) findViewById(R.id.your xml file);
mBlogList.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
mBlogList.setLayoutManager(mLayoutManager);//VERTICAL FORMAT
You could always have a datestamp in your objects and sort your listview based on that..
public class CustomComparator implements Comparator<YourObjectName> {
public int compare(YourObjectName o1, YourObjectName o2) {
return o1.getDate() > o2.getDate() // something like that.. google how to do a compare method on two dates
}
}
now sort your list
Collections.sort(YourList, new CustomComparator());
This should sort your list such that the newest item will go on top
You can always use a LinkedList instead and then use addFirst() method to add elements to your list and it will have the desired behaviour (new items at the top of the ListView).

Bring a selected ListView Item to the top

I have listviews inside a pager adapter, and I'm trying to make it so when I click on an item inside my listview, it will scroll that item to the top. I have an onclicklistener to the item, but I'm not sure how exactly to implement the scrolling given what I have.
public Object instantiateItem(ViewGroup container, int position) {
List<App> app = this.apps.get(position);
ListView list = new ListView(this.activity);
list.setAdapter(adapter);
container.addView(list);
return list;
}
First, use ListView's onItemClickListener.
Secondly, use the setSelected() method with the item's position (which you get on the listener).
smoothScrollToPosition
setSelectedPosition

Categories

Resources