Adapter cannot be applied to a recycleview search - android

I'm trying to call the SeachAdapter to my Activity but I can't get the list value because it displays can not be applied
Here is my activity code with same error
adapter = new SearchAdapter(this.mOwnerDao.getOwner());
recyclerView.setAdapter(adapter);
}
private void startSearch(String text) {
adapter = new SearchAdapter(this.mOwnerDao.getOwnerByName(text));
recyclerView.setAdapter(adapter);
}
My SearchAdapter
public class SearchAdapter extends RecyclerView.Adapter<SearchViewHolder>{
private Context context;
private List<Owner> owners;
public SearchAdapter(Context context, List<Owner> owners)
{
this.context = context;
this.owners = owners;
}
#Override
public SearchViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.layout_item,parent,false);
return new SearchViewHolder(itemView);
}
#Override
public void onBindViewHolder(SearchViewHolder holder, int position) {
holder.name.setText(owners.get(position).getName());
holder.phoneNumber.setText(owners.get(position).getPhoneNumber());
holder.address.setText(owners.get(position).getAddress());
}
#Override
public int getItemCount() {
return owners.size();
}
}

Try this: -
private void startSearch(String text) {
adapter = new SearchAdapter(this, this.mOwnerDao.getOwnerByName(text));
recyclerView.setAdapter(adapter);
}

I think you're missing Layout Manager to your recyclerview. Post more code. Sorry i don't have reputation to comment so posting as an answer

Pass this at first parameter in SearchAdapter function every time when you call this function
new SearchAdapter(this,this.mOwnerDao.getOwner());

Related

accessing an adapter's data via another adapter

Is it all possible to access an adapter's data via another adapter?
I want to start an activity and pass data from an adapter to a fragment which is used in TabLayout as one of three fragments, I have two adapters and a button which is clicked to start an activity, its Java code is in my first adapter and I need to pass second adapter's data via second adapter itself
here is my codes:
my first adapter:
public class RecyclerViewDataAdapter extends RecyclerView.Adapter<RecyclerViewDataAdapter.ItemRowHolder>{
private ArrayList<SectionDataModel> dataList;
private Context mContext;
private RecyclerView.RecycledViewPool recycledViewPool;
private SnapHelper snapHelper;
public RecyclerViewDataAdapter(ArrayList<SectionDataModel> dataList, Context mContext) {
this.dataList = dataList;
this.mContext = mContext;
recycledViewPool = new RecyclerView.RecycledViewPool();
}
#Override
public ItemRowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, null);
ItemRowHolder rowHolder = new ItemRowHolder(v);
snapHelper = new GravitySnapHelper(Gravity.START);
return rowHolder;
}
#Override
public void onBindViewHolder(ItemRowHolder holder, int position) {
ArrayList singleSectionItems = dataList.get(position).getAllItemInSection();
final String sectionName = dataList.get(position).getHeaderTitle();
holder.itemTitle.setText(sectionName);
SectionDataAdapter adapter = new SectionDataAdapter(singleSectionItems, mContext);
holder.recyclerView.setHasFixedSize(true);
holder.recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setAdapter(adapter);
holder.recyclerView.setRecycledViewPool(recycledViewPool);
snapHelper.attachToRecyclerView(holder.recyclerView);
holder.btnMore.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//here i can start the activity but..(second adapter)
Toast.makeText(view.getContext(), sectionName, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return (null != dataList ? dataList.size() : 0);
}
public class ItemRowHolder extends RecyclerView.ViewHolder {
protected ImageView mitemImage;
protected TextView mitemtext;
protected TextView itemTitle;
protected RecyclerView recyclerView;
protected Button btnMore;
public ItemRowHolder(View itemView) {
super(itemView);
this.mitemImage = itemView.findViewById(R.id.itemImage);
this.mitemtext = itemView.findViewById(R.id.tvTitle);
this.itemTitle = itemView.findViewById(R.id.itemTitle);
this.recyclerView = itemView.findViewById(R.id.recycler_view_list);
this.btnMore = itemView.findViewById(R.id.btnMore);
}
}
} '
and my second adapter:
import java.net.PortUnreachableException;
import java.util.ArrayList;
public class SectionDataAdapter extends RecyclerView.Adapter<SectionDataAdapter.SssingleItemRowHolder>{
private ArrayList<SingleItemModel> itemModels;
private Context mContext;
public SectionDataAdapter(ArrayList<SingleItemModel> itemModels, Context mContext) {
this.itemModels = itemModels;
this.mContext = mContext;
}
#Override
public SingleItemRowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_single_card, null);
SingleItemRowHolder singleItemRowHolder = new SingleItemRowHolder(v);
return singleItemRowHolder;
}
#Override
public void onBindViewHolder(SingleItemRowHolder holder, int position) {
SingleItemModel itemModel = itemModels.get(position);
holder.tvTitle.setText(itemModel.getName());
holder.mitemImage.setImageResource(itemModel.getImage());
}
#Override
public int getItemCount() {
return (null != itemModels ? itemModels.size() : 0);
}
public class SingleItemRowHolder extends RecyclerView.ViewHolder {
protected TextView tvTitle;
protected ImageView mitemImage;
public SingleItemRowHolder(View itemView) {
super(itemView);
final Intent intent = new Intent(mContext,MainActivity.class);
this.mitemImage = itemView.findViewById(R.id.itemImage);
this.tvTitle = itemView.findViewById(R.id.tvTitle);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//... need to start the activity from here
Toast.makeText(view.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show();
}
});
}
}
Like #MilaDroid said you simply need a getter that returns the another Adapter's ArrayList<SingleItemModel> but the problem you will face is that you need to have the same instance of the Adapter from the Activity in order to get the populated ArrayList<SingleItemModel>.
A good workaround is to used Bill Pugh's Singleton in the Adapter
public class Adapter {
private ArrayList<SingleItemModel> list;
private Adapter() {}
public static Adapter getInstance() {
return InstInit.INSTANCE;
}
// Don't forget to set the list (or NPE)
// because we can't argue with a Singleton
public void setList(ArrayList<SingleItemModel> list) {
this.list = list;
}
// You can now get the ArrayList
public ArrayList<SingleItemModel> getList() {
return list;
}
private static class InstInit {
private static final Adapter INSTANCE = new Adapter();
}
// Overrided RecyclerView.Adapter Methods
.................
}
Retrieving the ArrayList assuming that the following Adapters are Singleton
AdapterOne a1 = AdapterOne.getInstance();
AdapterTwo a2 = AdapterTwo.getInstance();
ArrayList<SingleItemModel> a1RetrievedList = a1.getList();
// You don't need to create a new instance
// creating a new instance doesn't make sense
// because you need to repopulate the list
// for the new instance.
ArrayList<SingleItemModel> a2RetrievedList = a2.getList();
// You can also retrieve from AdapterTwo

How to send data from recycler adapter to fragment | How to call fragment function from recyclerview adapter

I have code in Fragment:
InfoAdapter adapter = new InfoAdapter(getContext(), R.layout.lv_info, infoList );
listingsView = (RecyclerView) rootView.findViewById(R.id.lvInfo);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
listingsView.setLayoutManager(layoutManager);
listingsView.setHasFixedSize(true);
listingsView.setAdapter(adapter);
How do I process clicks on an items in this fragment?
Eg call function (function located in fragment) with ID item (eg public void onItemClick(int item_id) {} )
My adapter:
public class InfoAdapter extends RecyclerView.Adapter<InfoHolder> {
private final List<Info> infos;
private Context context;
private int itemResource;
public InfoAdapter(Context context, int itemResource, List<Info> infos) {
this.infos = infos;
this.context = context;
this.itemResource = itemResource;
}
#Override
public InfoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(this.itemResource, parent, false);
return new InfoHolder(this.context, view);
}
#Override
public void onBindViewHolder(InfoHolder holder, int position) {
Info info = this.infos.get(position);
holder.bindInfo(info);
}
#Override
public int getItemCount() {
return this.infos.size();
}
}
You can use interface to achieve your desired result.
Just declare an interface in your adapter with the parameters that you want to pass to your fragment. And in your fragment initialize the interface and pass it to your adapter's constructor.
You can do something like this:
In your Fragment
public class MainFragment extends Fragment {
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Pass your adapter interface in the constructor
InfoAdapter adapter = new InfoAdapter(getContext(), R.layout.lv_info, infoList, adapterInterface );
}
// This is the interface declared inside your adapter.
InfoAdapter.InfoAdapterInterface adapterInterface = new InfoAdapter.InfoAdapterInterface() {
#Override
public void OnItemClicked(int item_id) {
// Do whatever you wants to do with this data that is coming from your adapter
}
};
}
In your Adapter
public class InfoAdapter extends RecyclerView.Adapter<InfoHolder> {
private final List<Info> infos;
private Context context;
private int itemResource;
// Interface Object
private InfoAdapterInterface adapterInterface;
public InfoAdapter(Context context, int itemResource, List<Info> infos, InfoAdapterInterface adapterInterface) {
this.infos = infos;
this.context = context;
this.itemResource = itemResource;
// Initialize your interface to send updates to fragment.
this.adapterInterface = adapterInterface;
}
#Override
public InfoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(this.itemResource, parent, false);
return new InfoHolder(this.context, view);
}
#Override
public void onBindViewHolder(InfoHolder holder, int position) {
Info info = this.infos.get(position);
holder.bindInfo(info);
// You can pass any data here that is defined in your interface's params
adapterInterface.OnItemClicked(3);
}
#Override
public int getItemCount() {
return this.infos.size();
}
// Your interface to send data to your fragment
public interface InfoAdapterInterface{
void OnItemClicked(int item_id);
}
}
You can create multiple methods in your interface and can easily get the desired data inside your interface. Another trick can be using Abstract methods.
I hope this will help you. Let me know if you face any difficulty :)
Edit to show how to pass Interface from Adapter to ViewHolder
In your Adapter Class do this
#Override
public InfoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(this.itemResource, parent, false);
// Pass the interface that you've created in the constructor of your viewholder
return new InfoHolder(view, adapterInterface);
}
And in your ViewHolder you can get the interface like this and use it wherever you want inside your ViewHolder:
public class InfoHolder extends RecyclerView.ViewHolder {
public InfoHolder(View itemView, final InfoAdapter.InfoAdapterInterface adapterInterface) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
adapterInterface.OnItemClicked(2);
}
});
}
}
This should solve your problem with interfaces ^_^
In your method onBindViewHolder, set the onclicklistener in the binded view and pass its parameters trough Bundle.
Just pass Fragment instance to adapter.
For example :
IN FRAGMENT :
recyclerAdapter = new RecyclerAdapter(getActivity(), MyFragment.this);
recyclerView.setAdapter(recyclerAdapter);
recyclerAdapter.notifyDataSetChanged();
IN ADAPTER :
1. Create adapter constructer like
MyFragment myFragment;
public RecyclerAdapter(Context context, MyFragment myFragment){
this.context = context;
this.myFragment = myFragment;
}
under onBindViewHolder
call myFragment.yourMethodName;

Android RecyclerView does not update on data changed

The RecyclerView shows only items that was in ArrayList (data of the adapter) on creation. All my attempts to add more lines seems to work, but the list stays with initial data.
It isn't duplicate, as I tried all the suggestions found on google.
What I already did:
adapter.notifyDataSetChanged();
adapter.notifyItemChanged(5);
recycleList.invalidate();
recycleList.setAdapter(adapter);
running the update on UIThread with Handler
The adapter work as it should - onCreateView do it's work (creat new lines) as well as onBindView (bind new data). getItemCount() returns correct value (larger after update). Everything looks like it should be - instead of the final view - does not change.
The only thing that will work is recreate the adapter from scratch with new dataset - completely unacceptable by design (ugly on long lists).
Here is the code:
Create in fragment:
adapter = new MyListAdapter(getContext());
adapter.addItems(initialItems); // These and only these I see on the list
LinearLayoutManager mLayoutManager=new LinearLayoutManager(getContext());
recycleList.setLayoutManager(mLayoutManager);
recycleList.setAdapter(adapter);
Trying to update from fragment:
public void onUpdateReady(ArrayList<Model> freshData) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() { // UI thread
adapter.addItems(freshData);
adapter.notifyDataSetChanged();
adapter.notifyItemChanged(5);
recycleList.invalidate();
//notifyItemRangeInserted(3,freshData.size());
}
});
}
Adapter:
private Context mContext;
private ArrayList<Model> data;
public MyListAdapter(Context mContext) {
this.mContext = mContext;
data=new ArrayList<>();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.textName.setText(data.get(position).getName());
}
#Override
public int getItemCount() {
return data.size();
}
public void addItems(Collection<Model> list) {
data.addAll(list);
}
public class ViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.textName) TextView textName;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
}
}
UPDATE: Changed according to comments:
public void addItems(Collection<Model> list) {
ArrayList<Model> newData=new ArrayList<>(); // Make new array
newData.addAll(data); // Take old
newData.addAll(list); // Add new
data=newData; // change to data to newly created array
notifyDataSetChanged();
}
try this
In Fragment
ArrayList<Data> items=new ArrayList<>();
items.addAll(initialItems);
adapter = new MyListAdapter(getContext(),items);
LinearLayoutManager mLayoutManager=new LinearLayoutManager(getContext());
recycleList.setLayoutManager(mLayoutManager);
recycleList.setAdapter(adapter);
public void onUpdateReady(ArrayList<Model> freshData) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() { // UI thread
items.addAll(freshData);
adapter.notifyDataSetChanged();
followList.invalidate();
}
});
}
private Context mContext;
private ArrayList<Model> data;
public MyListAdapter(Context mContext,ArrayList<Model> data) {
this.mContext = mContext;
this.data=data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.textName.setText(data.get(position).getName());
}
#Override
public int getItemCount() {
return data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.textName) TextView textName;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
}
}
Change your Adapter constructor:
private ArrayList<Model> data;
public MyListAdapter(Context mContext,ArrayList<Model> data) {
this.mContext = mContext;
this.data = data;}
public void addItems(Collection<Model> list) {
data.addAll(list);
}
fragment:
adapter = new MyListAdapter(getContext(),initialItems);
I had a similar problem once and calling invalidateViews on the ListView worked, even if it was a hack. Instead of recycleList.invalidate(); try recycleList.invalidateViews();

RecycleView displays data only first time

I have a RecycleView to which I give an Array of Post objects. When it's loaded first time, everything works fine but trying to replace the data or just entering in the Fragment again then the RecycleView does not show anything. Also I have checked the size of the new data and it's different from zero. Here is my code:
// Init the list
list = (RecyclerView) view.findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(mContext));
...
if (adapter != null) {
adapter.replaceCurrentPosts(new ArrayList<>(postList));
}
else {
adapter = new PostAdapter(mContext, new ArrayList<>(postList), this);
list.setAdapter(adapter);
}
...
public PostAdapter(Context context, List<Post> posts, onPostElementClickListener listener) {
this.context = context;
this.posts = posts;
this.mListener = listener;
}
public void replaceCurrentPosts(List<Post> newPosts) {
this.posts.clear();
this.posts.addAll(newPosts);
this.notifyDataSetChanged();
}
#Override
public int getItemCount() {
return posts.size();
}
package com.example.jiteshmohite.myapplication;
public class PostAdapter extends RecyclerView.Adapter {
private Context context;
private List<Post> posts;
private onPostElementClickListener mListener;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
public ViewHolder(View v) {
super(v);
mTextView = (TextView) v.findViewById(R.id.info_text);
}
}
public PostAdapter(Context context, List<Post> posts, onPostElementClickListener listener) {
this.context = context;
this.posts = posts;
this.mListener = listener;
}
public void replaceCurrentPosts(List<Post> newPosts) {
posts.clear();
posts = newPosts;
this.notifyDataSetChanged();
}
#Override
public PostAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(PostAdapter.ViewHolder holder, final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.mTextView.setText(posts.get(position).getName());
holder.mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.onClick(position);
}
});
}
#Override
public int getItemCount() {
return posts.size();
}
interface onPostElementClickListener {
public void onClick(int pos);
}
}
private RecyclerView list;
private PostAdapter postAdapter;
private RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_example);
list = (RecyclerView) findViewById(R.id.list);
layoutManager = new LinearLayoutManager(getApplicationContext());
list.setLayoutManager(layoutManager);
postAdapter = new PostAdapter(getApplicationContext(), getPostData(), listener);
list.setAdapter(postAdapter);
}
private PostAdapter.onPostElementClickListener listener = new PostAdapter.onPostElementClickListener() {
#Override
public void onClick(int pos) {
Toast.makeText(getApplicationContext(), pos + "" , Toast.LENGTH_SHORT).show();
List<Post> posts = getPostData();
posts.get(pos).setName("abc");
postAdapter.replaceCurrentPosts(posts);
}
};
// get post list which contains name
public List<Post> getPostData() {
Post post = new Post();
post.setName("xyz");
List<Post> posts = new ArrayList<Post>();
posts.add(post);
posts.add(post);
posts.add(post);
posts.add(post);
posts.add(post);
return posts;
}
}
I suggesting rather then notifyDataSetChanged() you should refer notifyItemChange which modify specific positions.
please let me know if it is not work for you.
why don't you try to add one element (or maybe more) instead of remove all and re-add all items?

RecyclerView, slow scrollToPosition, setSelected

Prompt, faced with scrollToPosition speed. I RecyclerView 900 positions and need to quickly establish a position as scrollToPosition very slow, c ListView such problems were not setSelection working out perfectly. It is possible to accelerate the scrollToPosition?
public class EventAdapter extends RecyclerView.Adapter<EventAdapter.Holder> {
final static public String TAG = "EventAdapter";
Context context;
List<Event> items;
public EventAdapter(List<Event> items) {
this.items = items;
}
#Override
public EventAdapter.Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list_event, parent, false);
context = parent.getContext();
return new EventAdapter.Holder(v);
}
#Override
public void onBindViewHolder(EventAdapter.Holder holder, int position) {
holder.setModel(context, items.get(position), position);
}
#Override
public int getItemCount() {
return items.size();
}
public class Holder extends RecyclerView.ViewHolder {
public View block;
Holder(View view) {
super(view);
block = (View) view.findViewById(R.id.cv);
}
public void setModel(Context context, Event model, int position) {
}
}
}
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
rv.setLayoutManager(linearLayoutManager);
rv.setHasFixedSize(true);
linearLayoutManager.scrollToPosition(index);
There are couple of ways to do it:
1) Try smoothScrollToPosition as : [will certainly work]
Toast.makeText(this, "Scroll...", Toast.LENGTH_SHORT).show();
myList.smoothScrollToPosition(0);
2) Also read about scrollToPositionWithOffset as this may help too

Categories

Resources