Trying to create a generic adapter for the RecyclerView.
Already explored other solutions:
RecyclerView generic adapter with DataBinding
Add click listener to Generic RecyclerView Adapter
https://github.com/ravirupareliya/Recyclerview-Generic-Adapter/blob/master/app/src/main/java/com/rrr/genericrecyclerview/adapter/RecyclerAdapter.java
However want to implement it in a bit different way.
Here is how my adapter looks like:
public abstract class GenericAdapter<T> extends RecyclerView.Adapter<BaseHolder<T>> {
private OnRecyclerItemClickListener mListener;
private List<T> mItems;
private final LayoutInflater mLayoutInflater;
public GenericAdapter(Context context) {
mLayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mItems = Collections.emptyList();
}
#Override
public BaseHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
// assume that viewType is a resource id returned by getItemViewType
// also other solutions are welcome
View view = mLayoutInflater.inflate(viewType, parent, false);
// TODO: how to create the view holder ??
}
#Override
public void onBindViewHolder(BaseHolder<T> holder, int position) {
T item = mItems.get(position);
holder.onBind(item, mListener);
}
#Override
public int getItemCount() {
return mItems != null ? mItems.size() : 0;
}
public void setItems(List<T> items) {
mItems = items;
notifyDataSetChanged();
}
public void setItemClickListener(OnRecyclerItemClickListener listener) {
mListener = listener;
}
}
This is a base view holder from which I want to extend all other holders:
public abstract class BaseHolder<T> extends RecyclerView.ViewHolder {
public BaseHolder(View itemView) {
super(itemView);
}
public abstract void onBind(T item, OnRecyclerItemClickListener listener);
}
The problem is in onCreateViewHolder method.
How do I create the view holder?
Should I somehow implement abstract BaseHolder or should I somehow change the adapter class declaration extends i.e. instead BaseHolder here RecyclerView.Adapter> should be some generic implementation of BaseHolder? I tried > but it doesn't work
Thanks in advance for any piece of advice
P.S. It's been a long time, but if someone is interested,
at the time I solved it and published in a Generic RecyclerView Adapter library.
It finally makes it quite easy to create adapters.
I am still using it in multiple production projects.
EDIT:
So the adapter finally looks like:
public abstract class GenericRecyclerViewAdapter<T, L extends BaseRecyclerListener, VH extends BaseViewHolder<T, L>> extends RecyclerView.Adapter<VH> {
#Override
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
// ...
}
Thus, ViewHolder creation is delegated to the adapter implementation, i.e.:
public class SimpleAdapter extends GenericRecyclerViewAdapter<User, OnRecyclerItemClickListener, UserViewHolder> {
// ...
#Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// or return here any specific ViewHolder according to the viewType
return new UserViewHolder(inflate(R.layout.item_user, parent), getListener());
}
}
And the ViewHolder is a:
public abstract class BaseViewHolder<T, L extends BaseRecyclerListener> extends RecyclerView.ViewHolder {
// ...
}
This is what I did in my "Generic Adapter":
You pass the Class of your holder which is corresponding to your current View like this:
public class FooHolder extends BaseHolder<Foo> {
... // your code with the constructor matching super goes here
}
Then in your adapter constructor you add a parameter as follows:
public GenericAdapter(Context context, Class<? extends BaseHolder> holderClass) {
...
this.holderClass = holderClass;
}
Then in your onCreateViewHolder method you can make an instance of that class like this:
#Override
public BaseHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
...
viewHolder = (BaseHolder) holderClass.getConstructor(View.class).newInstance(view);
}
If you wants to use single generic adapter which have different-2 layouts items and different models for different screen, you need to try this :
Create a java class adapter "StoreListAdapter.java"
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collection;
/**
* Created by Deepak Sharma on 31/10/17.
*/
public class StoreListAdapter<T> extends RecyclerView.Adapter<StoreListAdapter.ViewHolder> implements Filterable {
private Collection<T> mItems;
private Context context;
private int mLayout;
IClickable iClickable;
private boolean isAnimationAllowed;
private StoreSearchFilter<T> mSearchFilter;
public StoreListAdapter(Context context)
{
this.context = context;
}
public void setData(Collection<T> items, boolean isAnimationAllowed)
{
mItems = items;
this.isAnimationAllowed = isAnimationAllowed;
}
public void setCallback(int layout, IClickable iClickable)
{
this.mLayout = layout;
this.iClickable = iClickable;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(mLayout, viewGroup, false);
iClickable.init(view);
StoreListAdapter.ViewHolder viewHolder = new StoreListAdapter.ViewHolder(view);
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
// viewHolder.itemView.getLayoutParams().width = width;
viewHolder.itemView.getLayoutParams().height = height+24;
return viewHolder;
}
#Override
public void onBindViewHolder(StoreListAdapter.ViewHolder viewHolder, int i) {
iClickable.execute(viewHolder, mItems.toArray()[i],viewHolder.getAdapterPosition());
if (isAnimationAllowed)
setAnimation(viewHolder.itemView, i);
}
#Override
public int getItemCount() {
return mItems.size()>0?mItems.size():0;
}
#Override
public Filter getFilter() {
if (mSearchFilter == null)
mSearchFilter = new StoreSearchFilter<T>((ArrayList<StoreModel>) mItems, new IFilteredList<T>() {
#Override
public void onListFiltered(ArrayList<T> list) {
setData(list, false);
notifyDataSetChanged();
}
});
return mSearchFilter;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mTextView;
//private CheckBox mCheckBox;
ViewHolder(View v) {
super(v);
mTextView = (TextView)v.findViewById(R.id.list_item);
}
}
public interface IClickable<T> {
public void init(View view);
public void execute(StoreListAdapter.ViewHolder holder, T object, int position);
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
/*if (position > lastPosition)
{*/
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
//lastPosition = position;
/*}*/
}
}
create a store model "StoreModel.java":
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Deepak Sharma on 31/10/17.
*/
public class StoreModel implements Parcelable {
private String storeName;
private int storeId;
private String storeAddress;
private String storePhone = "(310)816-2365";
private String storeCity;
private int prizesAvailable;
private double storeLatitude;
private double storeLongitude;
private List<Games> gamesList;
public StoreModel(int id,String sName, String add, String city, int prizes, double lat, double lon, ArrayList<Games> list)
{
this.storeId = id;
this.storeName = sName;
this.storeAddress = add;
this.storeCity = city;
this.prizesAvailable = prizes;
this.storeLatitude = lat;
this.storeLongitude = lon;
this.gamesList = list;
}
public String getStoreName() {
return storeName;
}
public void setStoreName(String storeName) {
this.storeName = storeName;
}
public String getStoreAddress() {
return storeAddress;
}
public void setStoreAddress(String storeAddress) {
this.storeAddress = storeAddress;
}
public String getStoreCity() {
return storeCity;
}
public void setStoreCity(String storeCity) {
this.storeCity = storeCity;
}
public int getPrizesAvailable() {
return prizesAvailable;
}
public void setPrizesAvailable(int prizesAvailable) {
this.prizesAvailable = prizesAvailable;
}
public double getStoreLatitude() {
return storeLatitude;
}
public void setStoreLatitude(double storeLatitude) {
this.storeLatitude = storeLatitude;
}
public double getStoreLongitude() {
return storeLongitude;
}
public void setStoreLongitude(double storeLongitude) {
this.storeLongitude = storeLongitude;
}
public List<Games> getGamesList() {
return gamesList;
}
public void setGamesList(List<Games> gamesList) {
this.gamesList = gamesList;
}
public String getStorePhone() {
return storePhone;
}
public void setStorePhone(String storePhone) {
this.storePhone = storePhone;
}
#Override
public boolean equals(Object obj) {
if (obj == this)
return true; //If objects equal, is OK
if (obj == null)
return false;
if (!(obj instanceof StoreModel))
return false;
if (obj instanceof StoreModel) {
StoreModel store = (StoreModel)obj;
return ((storeId == store.storeId) && (storeName.equalsIgnoreCase(store.storeName)));
// return (storeId == store.storeId) && y == store.y);
}
return false;
}
#Override
public int hashCode() {
return storeId;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.storeName);
dest.writeString(this.storeAddress);
dest.writeString(this.storePhone);
dest.writeString(this.storeCity);
dest.writeInt(this.prizesAvailable);
dest.writeDouble(this.storeLatitude);
dest.writeDouble(this.storeLongitude);
dest.writeList(this.gamesList);
}
protected StoreModel(Parcel in) {
this.storeName = in.readString();
this.storeAddress = in.readString();
this.storePhone = in.readString();
this.storeCity = in.readString();
this.prizesAvailable = in.readInt();
this.storeLatitude = in.readDouble();
this.storeLongitude = in.readDouble();
this.gamesList = new ArrayList<Games>();
in.readList(this.gamesList, Games.class.getClassLoader());
}
public static final Parcelable.Creator<StoreModel> CREATOR = new Parcelable.Creator<StoreModel>() {
#Override
public StoreModel createFromParcel(Parcel source) {
return new StoreModel(source);
}
#Override
public StoreModel[] newArray(int size) {
return new StoreModel[size];
}
};
}
Create a "store_item.xml" :
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coordinator_game_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/store_item_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="#android:color/transparent"
card_view:cardElevation="0dp"
android:layout_marginTop="#dimen/dp_five">
<TextView
android:id="#+id/txtStoreName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Store Name"
android:textSize="18sp" />
</android.support.v7.widget.CardView>
</android.support.design.widget.CoordinatorLayout>
Now in you Activity or Fragment class, call this method to set Adapter:
private void setBottomViewAdapter() {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerStore.setHasFixedSize(true);
// use a linear layout manager
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerStore.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mStoreList = new ArrayList<>();
mStoreList.add(new StoreModel(1001, "Von's", "9860 National Blvd., Los Angeles", "Culver City", 12, 28.624035, 77.365541, getGamesList(8)));
mStoreList.add(new StoreModel(1002, "Jack", "1311 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.622665, 77.364082, getGamesList(6)));
mStoreList.add(new StoreModel(1003, "Ian", "1430 S Fairfax Ave., Los Angeles", "Culver City", 8, 28.620899, 77.365258, getGamesList(2)));
mStoreList.add(new StoreModel(1004, "Jessica Alberto", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.623890, 77.374136, getGamesList(10)));
mStoreList.add(new StoreModel(1005, "Robert", "2545 National Blvd, Los Angeles", "Culver City", 6, 28.631175, 77.375661, getGamesList(4)));
mStoreList.add(new StoreModel(1006, "Clark", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.627153, 77.381809, getGamesList(11)));
mStoreList.add(new StoreModel(1007, "Jason", "9860 National Blvd., Los Angeles", "Culver City", 12, 28.626569, 77.371963, getGamesList(3)));
mStoreList.add(new StoreModel(1008, "Papon", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.623155, 77.371677, getGamesList(2)));
mStoreList.add(new StoreModel(1009, "Von's", "2545 National Blvd, Los Angeles", "Culver City", 11, 28.611569, 77.38545, getGamesList(13)));
mStoreList.add(new StoreModel(1010, "Robert Downey Jr.", "1430 S Fairfax Ave., Los Angeles", "Culver City", 8, 28.623127, 77.369113, getGamesList(4)));
mStoreList.add(new StoreModel(1011, "Ben Affleck", "1335 Wilshire Blvd., Santa Monica", "Mid City", 4, 28.62373, 77.39452, getGamesList(12)));
mStoreListAdapter = new StoreListAdapter(getActivity());
boolean isAnimate = false;
mStoreListAdapter.setData(mStoreList, isAnimate);
mStoreListAdapter.setCallback(R.layout.store_item, new StoreListAdapter.IClickable() {
#Override
public void init(View view) {
// Toast.makeText(getActivity(), "Initialized", Toast.LENGTH_SHORT).show();
}
#Override
public void execute(StoreListAdapter.ViewHolder viewHolder, Object object, int position) {
final StoreModel model = (StoreModel) object;
View view = viewHolder.itemView;
StoreListAdapter.ViewHolder holder = viewHolder;
final CoordinatorLayout fabGameview = (CoordinatorLayout) view;
final CardView cardView = (CardView) fabGameview.findViewById(R.id.store_item_cardview);
TextView txtStoreName = (TextView) cardView.findViewById(R.id.txtStoreName);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isAddedToBackStack = true;
StoreDetailsAndProductListFragment storeDetailsAndProductListFragment = new StoreDetailsAndProductListFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(ExtrasUtil.STORE, model);
storeDetailsAndProductListFragment.setArguments(bundle);
showOtherFragment(storeDetailsAndProductListFragment, getActivity().getFragmentManager(), isAddedToBackStack);
}
});
}
});
mRecyclerStore.setAdapter(mStoreListAdapter);
}
Create an interface :
import java.util.ArrayList;
/**
* Created by Deepak Sharma on 3/8/2017.
*/
public interface IFilteredList<T> {
public void onListFiltered(ArrayList<T> list);
}
Create a custom Filterable class StoreSearchFilter.java:
import android.widget.Filter;
import java.util.ArrayList;
import java.util.List;
public final class StoreSearchFilter<T> {
// private final Pattern pattern;
private ArrayList<StoreModel> mList;
private IFilteredList<T> callback;
public StoreSearchFilter(final String regex)
{
// pattern = Pattern.compile(regex);
}
public StoreSearchFilter(ArrayList<StoreModel> list, IFilteredList<T> listener)
{
this.mList = list;
this.callback = listener;
}
#Override
protected Filter.FilterResults performFiltering(CharSequence constraint) {
Filter.FilterResults results = new Filter.FilterResults();
if (constraint == null || constraint.length() == 0) {
results.values = mList;
results.count = mList.size();
}
else {
// Some search copnstraint has been passed
// so let's filter accordingly
ArrayList<StoreModel> filteredContacts = new ArrayList<StoreModel>();
if (mList!=null && mList.size()>0)
{
// We'll go through all the contacts and see
// if they contain the supplied string
for (StoreModel model : mList) {
// TODO Here search for the store name match
if (model.getStoreName().toUpperCase().contains(constraint.toString().toUpperCase())) {
// if `contains` == true then add it
// to our filtered list
filteredContacts.add(model);
}
// TODO Here search for the product name match
else {
List<Games> gameList = model.getGamesList();
if (gameList!=null && gameList.size()>0)
{
for (Games game : gameList) {
if (game.getProductName().toUpperCase().contains(constraint.toString().toUpperCase())) {
filteredContacts.add(model);
break;
}
}
}
}
}
}
// Finally set the filtered values and size/count
results.values = filteredContacts;
results.count = filteredContacts.size();
}
// Return our FilterResults object
return results;
}
#Override
protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
callback.onListFiltered((ArrayList<T>) results.values);
}
}
Related
I would like to update panel wise items in inner adapter item android recyclerview. When we pass the data dynamically.Data displaying is working fine. When we go to update the inner adapter item, it's not getting updated. But last item was getting update fine.
Activity.
public class PannelCreation extends AppCompatActivity {
RecyclerView userPanelRecycler;
List<String> roomPanels = new ArrayList<>();
List<JSONObject> roomItemObject = new ArrayList<JSONObject>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pannel_creation);
userPanelRecycler = findViewById(R.id.user_panel_recycler);
for(int i=0; i<=5;i++){
roomPanels.add("Panels "+i)
}
PanelAdapter panelAdapter = new PanelAdapter(getApplicationContext(),roomPanels);
userPanelRecycler.setLayoutManager(new LinearLayoutManager(this));
userPanelRecycler.setHasFixedSize(true);
userPanelRecycler.setAdapter(panelAdapter);
}
}
// OuterAdapter
class PanelAdapter extends RecyclerView.Adapter<PanelAdapter.ViewHolder>{
Context context;
List<String> roomPanelList;
RecyclerView.RecycledViewPool recycledViewPool;
List<ItemData> itemDataList = new ArrayList<>();
public PanelAdapter(Context context, List<String> roomPanels) {
this.context = context;
this.roomPanelList = roomPanels;
recycledViewPool = new RecyclerView.RecycledViewPool();
}
#NonNull
#Override
public PanelAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.panel_wise_layout,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
viewHolder.itemsRecycler.setRecycledViewPool(recycledViewPool);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull PanelAdapter.ViewHolder holder, int position) {
holder.userPanelName.setText(roomPanelList.get(position));
String cur_panelName = roomPanelList.get(position);
itemsAdapter = new ItemsAdapter(context);
holder.itemsRecycler.setLayoutManager(new GridLayoutManager(context,3));
holder. itemsRecycler.setHasFixedSize(true);
holder.itemsRecycler.setAdapter(itemsAdapter);
holder.itemsRecycler.setNestedScrollingEnabled(false);
try {
roomItemObject.clear();
JSONArray metaArray = new JSONArray(metaData);
int count = 0;
for(int i = 0;i<metaArray.length();i++){
JSONObject object = metaArray.getJSONObject(i);
String name = object.getString("name");
String[] rNum = name.split("_");
if(rNum[0].equalsIgnoreCase(roomNumber)){
roomItemObject.add(object);
}
count = count+1;
}
if(count == metaArray.length()){
int count1 = 0;
itemDataList.clear();
for(int i =0; i < roomItemObject.size();i++){
JSONObject itemObject1 = roomItemObject.get(i);
String groupNames = itemObject1.getString("groupNames");
String types = itemObject1.getString("type");
String metaValue = itemObject1.getString("metadata");
JSONObject panelObject = new JSONObject(metaValue);
String panel_name = panelObject.getString("panelName");
JSONObject valueObject = new JSONObject(panel_name);
String value = valueObject.getString("value");
if(value.equalsIgnoreCase(cur_panelName)){
String labels = itemObject1.getString("label");
String names = itemObject1.getString("name");
String state = itemObject1.getString("state");
String groupName = itemObject1.getString("groupNames");
String tags = itemObject1.getString("tags");
ItemData itemData = new ItemData();
itemData.setLabelName(labels);
itemData.setState(state);
itemData.setItemName(names);
itemData.setTags(tags);
itemData.setTypes(types);
itemData.setGroup(groupName);
itemDataList.add(itemData);
itemsAdapter.addItems(itemDataList);
itemsAdapter.notifyDataSetChanged();
}
}
}
}catch (JSONException e){
e.printStackTrace();
}
}
#Override
public int getItemCount() {
return roomPanelList.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
public class ViewHolder extends RecyclerView.ViewHolder{
RecyclerView itemsRecycler;
TextView userPanelName;
Button deletePanel;
public ViewHolder(#NonNull View itemView) {
super(itemView);
itemsRecycler = itemView.findViewById(R.id.panel_item_recycler);
userPanelName = itemView.findViewById(R.id.test_panel_name);
deletePanel = itemView.findViewById(R.id.delete_panel);
}
}
}
//Inner Adapter
class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ItemHolder>{
Context mContext;
List<ItemData> innerItemDataList = new ArrayList<>();
List<JSONObject> itemObjectList = new ArrayList<JSONObject>();
List<JSONObject> recObjectList = new ArrayList<>();
ItemData itemData;
public ItemsAdapter(Context context) {
this.mContext = context;
this.itemData = new ItemData();
}
public void addItems(List<ItemData> itemData){
this.innerItemDataList.clear();
this.innerItemDataList.addAll(itemData);
notifyDataSetChanged();
}
#NonNull
#Override
public ItemsAdapter.ItemHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.panel_wise_item,parent,false);
return new ItemHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ItemHolder holder, int position) {
itemData = innerItemDataList.get(position);
if(itemData != null){
holder.itemNames.setText(itemData.getLabelName());
}
#Override
public int getItemCount() {
return innerItemDataList.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
public class ItemHolder extends RecyclerView.ViewHolder {
TextView itemNames;
LinearLayout itemLayout;
ImageView itemImg;
public ItemHolder(#NonNull View itemView) {
super(itemView);
itemNames = itemView.findViewById(R.id.panel_item_name);
itemLayout = itemView.findViewById(R.id.panel_light_linear);
itemImg = itemView.findViewById(R.id.panel_item_img);
}
}
public void updateItem(String itemName,String state){
for(int j=0;j<innerItemDataList.size();j++){
if(itemName.equalsIgnoreCase(innerItemDataList.get(j).getItemName())){
innerItemDataList.get(j).setState(state);
notifyDataSetChanged();
}
}
}
}
//Inner adapter data model class
public class ItemData {
String labelName;
String itemName;
String state;
String group;
String tags;
String types;
public String getTypes() {
return types;
}
public void setTypes(String types) {
this.types = types;
}
public String getTags() {
return tags;
}
public void setTags(String tags) {
this.tags = tags;
}
public String getLabelName() {
return labelName;
}
public void setLabelName(String labelName) {
this.labelName = labelName;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
}
How to update specific item in inner adapter android nested recycler view.Can anyone guide me how to deal with update specific item. One more thing have observed inner adapter returns last position of array list only. Items are updating fine in last position of array list. When trying to updating the rest of position array list items, not getting updated.
Thanks in Advance.
Amar.
In outer adapter when ever data changes need to notify. Try this code
panelAdapter.notifyDataSetChanged();
I got this searchView which I use to filter recyclerView. So when there is no results for some search query, I want to show textView to user by setting its visibility to VISIBLE. So in searchView listener, I do:
#Override
public boolean onQueryTextChange(String s) {
adapter.getFilter().filter(s);
if (adapter.getItemCount()<=0){
emptyStateConatiner.setVisibility(View.VISIBLE);
}
else emptyStateConatiner.setVisibility(View.GONE);
return false;
}
But this doesn't work as I would expect, because when I type non existing search query, it first shows empty recyclerView and only after that, if I type additional letter to that query, I get emptyStateContainer shown.
Does anyone know what is causing this behavior?
Here is adapter code:
package com.app.userprofile;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.Filter;
import android.widget.Filterable;
import com.app.R;
import com.app.data.webservice.collection_response.Datum;
import java.util.ArrayList;
import java.util.List;
public class BasicUserProfileInfoListAdapter extends RecyclerView.Adapter<BasicUserProfileInfoListAdapter.BasicInfoViewHolder> implements Filterable {
private List<Datum> offeredChoices = new ArrayList<>();
private List<Datum> offeredChoicesFiltered = new ArrayList<>();
private List<Datum> previouslySelectedChoices = new ArrayList<>();
private Resources resources;
private ItemClickCallback clickCallback;
//for single choices
int mCheckedPostion=-1;
public BasicUserProfileInfoListAdapter(ItemClickCallback clickCallback){
this.clickCallback = clickCallback;
}
public void setList(List<Datum> datumList) {
this.offeredChoices = datumList;
this.offeredChoicesFiltered = datumList;
notifyDataSetChanged();
}
#NonNull
#Override
public BasicInfoViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.basic_choice_item, viewGroup, false);
if (resources == null) {
resources = itemView.getContext().getApplicationContext().getResources();
}
return new BasicInfoViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull final BasicInfoViewHolder basicInfoViewHolder, final int i) {
final Datum currentData = offeredChoicesFiltered.get(i);
basicInfoViewHolder.basicInfoCheckBox.setText(currentData.getDesc());
//TODO if currentData equals some choice in previouslySelectedChoices, than mark it checked and add it to selected choices via interface
if (clickCallback instanceof MultipleChoiceItemClickCallback && previouslySelectedChoices!=null && !previouslySelectedChoices.isEmpty()){
boolean shouldCheck=false;
for (Datum data:previouslySelectedChoices) {
if ((data.getId().equals(currentData.getId()))/*&& data.getDesc().equals(currentData.getDesc())*/){
shouldCheck=true;
clickCallback.onRowClicked(currentData,ChoiceClickType.ADD_CHOICE);
}
}
basicInfoViewHolder.basicInfoCheckBox.setChecked(shouldCheck);
}
if (clickCallback instanceof SingleChoiceItemClickCallback){
basicInfoViewHolder.basicInfoCheckBox.setChecked(i == mCheckedPostion);
if (previouslySelectedChoices!=null && !previouslySelectedChoices.isEmpty()){
boolean shouldCheck=false;
for (Datum data:previouslySelectedChoices) {
if ((data.getId().equals(currentData.getId()))/*&& data.getDesc().equals(currentData.getDesc())*/){
shouldCheck=true;
previouslySelectedChoices.clear();//so it wouldn't reselect on notifyDataSetChanged()
clickCallback.onRowClicked(currentData,ChoiceClickType.ADD_SINGLE_CHOICE);
}
}
if (shouldCheck) mCheckedPostion = i;
//Log.d("slctdwf","choice: "+ currentData.getDesc()+", position: "+mCheckedPostion);
basicInfoViewHolder.basicInfoCheckBox.setChecked(shouldCheck);
}
}
}
#Override
public int getItemCount() {
if (offeredChoicesFiltered!=null) return offeredChoicesFiltered.size();
else return 0;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
private Datum getCurrentRowInfo(int position) {
return offeredChoicesFiltered.get(position);
}
public void setPreviouslySelectedChoices (List<Datum> data) {
if (data!=null && !data.isEmpty()){
this.previouslySelectedChoices = data;
notifyDataSetChanged();
}
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString();
List<Datum> filteredList = new ArrayList<>();
if (charString.isEmpty()) {
filteredList = offeredChoices;
} else {
for (Datum choice : offeredChoices) {
if (choice.getDesc().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(choice);
}
}
}
FilterResults filterResults = new FilterResults();
filterResults.count = filteredList.size();
filterResults.values = filteredList;
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
offeredChoicesFiltered = (ArrayList<Datum>) results.values;
notifyDataSetChanged();
}
};
}
class BasicInfoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private CheckBox basicInfoCheckBox;
private CardView entireRowCardView;
BasicInfoViewHolder(View itemView) {
super(itemView);
basicInfoCheckBox = itemView.findViewById(R.id.choice_checkbox);
entireRowCardView = itemView.findViewById(R.id.entire_row_basic_choice);
entireRowCardView.setOnClickListener(this);
if (resources == null) {
resources = itemView.getResources();
}
}
#Override
public void onClick(View v) {
Datum currentChoice = getCurrentRowInfo(getAdapterPosition());
int position = getAdapterPosition();
if (clickCallback instanceof MultipleChoiceItemClickCallback){
if (basicInfoCheckBox.isChecked()){
basicInfoCheckBox.setChecked(false);
clickCallback.onRowClicked(currentChoice, ChoiceClickType.REMOVE_CHOICE);
}
else if (!basicInfoCheckBox.isChecked()){
basicInfoCheckBox.setChecked(true);
clickCallback.onRowClicked(currentChoice, ChoiceClickType.ADD_CHOICE);
}
}
if (clickCallback instanceof SingleChoiceItemClickCallback){
if (position == mCheckedPostion) {
mCheckedPostion = -1;
//Log.d("slctdwf","removed single choice: "+ currentChoice.getDesc());
clickCallback.onRowClicked(currentChoice, ChoiceClickType.REMOVE_SINGLE_CHOICE);
basicInfoCheckBox.setChecked(false);
notifyDataSetChanged();
} else {
mCheckedPostion = position;
//Log.d("slctdwf","added single choice: "+ currentChoice.getDesc());
clickCallback.onRowClicked(currentChoice, ChoiceClickType.ADD_SINGLE_CHOICE);
basicInfoCheckBox.setChecked(true);
notifyDataSetChanged();
}
}
}
}
public interface ItemClickCallback {
void onRowClicked(Datum choiceData, ChoiceClickType choiceClickType);
}
public interface MultipleChoiceItemClickCallback extends ItemClickCallback{
void onRowClicked(Datum choiceData, ChoiceClickType choiceClickType);
}
public interface SingleChoiceItemClickCallback extends ItemClickCallback {
void onRowClicked(Datum choiceData, ChoiceClickType choiceClickType);
}
public enum ChoiceClickType {
ADD_CHOICE,
REMOVE_CHOICE,
ADD_SINGLE_CHOICE,
REMOVE_SINGLE_CHOICE
}
}
I think the onQueryChanged callback is the wrong place to control the empty state. You could use a DataSetObserver (documentation) to listen to list changes so you always have the correct size() of matches.
Register an observer that is called when changes happen to the data used by this adapter.
adapter.registerDataSetObserver(new DataSetObserver() {
#Override public void onChanged() {
super.onChanged();
showEmptyStateIfAdapterIsEmpty();
// access adapter's dataset size here or in that method
}
});
Goal: keep track of selected items of a recyclerview using a changing Imageview for each row. Pratically i'm implementing a sort of checkbox.
Checking works fine:
but when I try to search for some items, checked items change: only first item of my list is checked:
I'll post my code below:
Shop Selected Interface
public interface NearestShopActivityAdapterListener {
void onShopSelected(FShop shop, View view);
}
My View Holder
public class MyHolder extends RecyclerView.ViewHolder{
public TextView name, address;
public ImageView logo;
public MyHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.activityNearestShopListItemUhop);
address = (TextView) itemView.findViewById(R.id.activityNearestShopListItemAddress);
logo = (ImageView) itemView.findViewById(R.id.activityNearestShopListItemImage);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.onShopSelected(filteredShopList.get(getAdapterPosition()),view);
}
});
}
onShopSelected function
#Override
public void onShopSelected(FShop shop, View view) {
if(checkList.contains(shop.getShopId())){
mImgViewCheckBox = (ImageView) view.findViewById(R.id.checkBoxNearestShop);
mImgViewCheckBox.setImageResource(R.drawable.checkbox_selector_not_checked);
checkList.remove(shop.getShopId());
}else {
mImgViewCheckBox = (ImageView) view.findViewById(R.id.checkBoxNearestShop);
mImgViewCheckBox.setImageResource(R.drawable.ic_checked);
checkList.add(shop.getShopId());
}
}
Where I am wrong? I would try to associate the ImageView mImgViewCheckBox with the Shop id and not with its position in the recyclerview, but I have no idea on how to do it.
Thnak you in advance.
i have done this things in contact details. i provide my adapter and method you can change code your according needs .
InviteContactAdapter.java
public class InviteContactAdapter extends RecyclerView.Adapter<InviteContactAdapter.ItemViewHolder> implements Filterable {
private List<UserContact> mContactList = new ArrayList<>();
private List<UserContact> mContectFilter = new ArrayList<>();
private Context mContext;
private CustomFilter mFilter;
public List<String> mEmailList = new ArrayList<>();
public InviteContactAdapter(Context context, List<UserContact> mContactList) {
mContext = context;
this.mContactList = mContactList;
this.mContectFilter = mContactList;
mFilter = new CustomFilter();
}
public onItemClickListener onItemClickListener;
public void setOnItemClickListener(InviteContactAdapter.onItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.invite_contact_row_layout, viewGroup, false);
return new ItemViewHolder(view);
}
public interface onItemClickListener {
void onClick(UserContact contact);
}
#Override
public Filter getFilter() {
return mFilter;
}
#Override
public void onBindViewHolder(final ItemViewHolder itemViewHolder, int i) {
final UserContact contact = mContectFilter.get(i);
itemViewHolder.mTvUserNane.setText(contact.getUserName().trim());
itemViewHolder.mTvUserEmail.setText(contact.getUserEmail().trim());
if (contact.isSelect())
itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
else
itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (contact.isSelect()) {
contact.setSelect(false);
itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
} else {
contact.setSelect(true);
itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
}
}
});
}
#Override
public int getItemCount() {
return mContectFilter.size();
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView mTvUserNane, mTvUserEmail;
private ImageView mIvSelect;
public ItemViewHolder(View itemView) {
super(itemView);
mTvUserEmail = itemView.findViewById(R.id.icrlTvUserEmail);
mTvUserNane = itemView.findViewById(R.id.icrlTvUserName);
mIvSelect = itemView.findViewById(R.id.icrlIvSelect);
}
}
public List<String> getEmail() {
mEmailList.clear();
for (UserContact contact : mContectFilter) {
if (contact.isSelect()) {
mEmailList.add(contact.getUserEmail());
}
}
return mEmailList;
}
/**
* this class for filter data.
*/
class CustomFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults results = new FilterResults();
if (charSequence != null && charSequence.length() > 0) {
ArrayList<UserContact> filters = new ArrayList<>();
charSequence = charSequence.toString().toUpperCase();
for (int i = 0; i < mContactList.size(); i++) {
if (mContactList.get(i).getUserName().toUpperCase().contains(charSequence) || mContactList.get(i).getUserEmail().toUpperCase().contains(charSequence)) {
UserContact contact = new UserContact();
contact.setUserName(mContactList.get(i).getUserName());
contact.setUserEmail(mContactList.get(i).getUserEmail());
filters.add(contact);
}
}
results.count = filters.size();
results.values = filters;
} else {
results.count = mContactList.size();
results.values = mContactList;
}
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mContectFilter = (ArrayList<UserContact>) filterResults.values;
notifyDataSetChanged();
}
}
}
then after bind contact data into recycler view and search data based on name and email..
make set adapter method ..
private void setAdapter(){
if (!mContactList.isEmpty()) {
inviteContactAdapter = new InviteContactAdapter(getActivity(), mContactList);
mRvData.setAdapter(inviteContactAdapter);
inviteContactAdapter.setOnItemClickListener(new InviteContactAdapter.onItemClickListener() {
#Override
public void onClick(UserContact contact) {
mEmailList.add(contact.getUserEmail());
}
});
} else {
mTvEmpty.setVisibility(View.VISIBLE);
}
}
then after make search data method ...
/**
* this method sort data.
*/
private void sortData(View root) {
mEtSearchData = (EditText) root.findViewById(R.id.icffEtSearch);
mEtSearchData.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (inviteContactAdapter != null) {
inviteContactAdapter.getFilter().filter(s);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
after getting contact data it will be work. and you can change code your according.
i have also some lets say template that I am using every time when I need recycler view.
The diffrence is that I am using one more additional property in every item of list, so basically you are not depending on filtering, sorting or something else.
This is XML for activity:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.arnela.nihad.expresssaladbar.RecyclerViewExample.RecyclerViewActivity">
<SearchView
android:id="#+id/searchViewBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:iconifiedByDefault="false"
android:queryHint="HINT"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/searchViewBox" />
</android.support.constraint.ConstraintLayout>
Java class of RecyclerViewActivity is next one:
public class RecyclerViewActivity extends AppCompatActivity {
private RecyclerView mRecyclerList;
private RecyclerViewAdapter mRecyclerAdapter;
private List<DataVm> mSourceList = new ArrayList<>();
private SearchView txtSearchBox;
private Data data;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyler_view);
data = new Data();
mSourceList.addAll(data.getSourceList(""));
// this is recycler view from xml
mRecyclerList = findViewById(R.id.recycler_view);
InitRecyclerView();
txtSearchBox = findViewById(R.id.searchViewBox);
txtSearchBox.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
mSourceList.clear();
mSourceList.addAll(data.getSourceList(s));
mRecyclerAdapter.notifyDataSetChanged();
return false;
}
#Override
public boolean onQueryTextChange(String s) {
mSourceList.clear();
mSourceList.addAll(data.getSourceList(s));
mRecyclerAdapter.notifyDataSetChanged();
return false;
}
});
}
public void InitRecyclerView() {
mRecyclerList.setLayoutManager(new LinearLayoutManager(RecyclerViewActivity.this));
mRecyclerAdapter = new RecyclerViewAdapter(mSourceList, new IClickListenerAddRemove() {
#Override
public void onPositionClicked(int position, boolean isPicked) {
mSourceList.get(position).setPicked(isPicked);
}
});
mRecyclerList.setAdapter(mRecyclerAdapter);
}
}
Then, I have two helper class, one is for creating mockup data, with method for searching:
public class Data {
private List<DataVm> sourceList = null;
public Data() {
this.sourceList = new ArrayList<>();
// Items of the list and set all items to isPicked to false
sourceList.add(new DataVm(1, "Title 1", "Description 1", "", false));
sourceList.add(new DataVm(2, "Title 2", "Description 2", "", false));
sourceList.add(new DataVm(3, "Title 3", "Description 3", "", false));
sourceList.add(new DataVm(4, "Title 4", "Description 4", "", false));
sourceList.add(new DataVm(5, "Title 5", "Description 5", "", false));
sourceList.add(new DataVm(6 , "Title 6 ", "Description 6 ", "", false));
sourceList.add(new DataVm(7 , "Title 7 ", "Description 7 ", "", false));
sourceList.add(new DataVm(8 , "Title 8 ", "Description 8 ", "", false));
sourceList.add(new DataVm(9 , "Title 9 ", "Description 9 ", "", false));
sourceList.add(new DataVm(10, "Title 10", "Description 10", "", false));
sourceList.add(new DataVm(11, "Title 11", "Description 11", "", false));
sourceList.add(new DataVm(12, "Title 12", "Description 12", "", false));
}
public List<DataVm> getSourceList(String searchTitle) {
if (searchTitle.equals(""))
return sourceList;
List<DataVm> filteredList = new ArrayList<>();
for (DataVm item : sourceList) {
if (item.getTitle().contains(searchTitle)) {
filteredList.add(item);
}
}
return filteredList;
}
public void setSourceList(List<DataVm> sourceList) {
this.sourceList = sourceList;
}
}
And second helper class is basically class item for each row:
public class DataVm {
private int ItemId;
private String Title;
private String Description;
private String Image;
private boolean IsPicked;
public DataVm (int itemId, String title, String description, String image, boolean isPicked) {
ItemId = itemId;
Title = title;
Description = description;
Image = image;
IsPicked = isPicked;
}
public int getItemId() {
return ItemId;
}
public void setItemId(int itemId) {
ItemId = itemId;
}
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getImage() {
return Image;
}
public void setImage(String image) {
Image = image;
}
public boolean isPicked() {
return IsPicked;
}
public void setPicked(boolean picked) {
IsPicked = picked;
}
}
Finally, two last classes are Adapter for list, and view holder for it.
Adapter class:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<DataVm> mItemList;
private IClickListenerAddRemove listener;
public RecyclerViewAdapter(List<DataVm> itemList, IClickListenerAddRemove listener) {
mItemList = itemList;
this.listener = listener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.salad_creation_item_template, parent, false);
return new RecyclerViewHolder(view, listener);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
RecyclerViewHolder holder = (RecyclerViewHolder) viewHolder;
DataVm item = mItemList.get(position);
holder.setTitle(item.getTitle());
holder.setDescription(item.getDescription());
holder.setIsPicked(item.isPicked());
if (item.isPicked())
holder.setButtonDrawable(R.drawable.ic_remove_24dp);
else
holder.setButtonDrawable(R.drawable.ic_add_24dp);
}
#Override
public int getItemCount() {
return mItemList == null ? 0 : mItemList.size();
}
}
And the last one is view holder for list:
public class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView txtTitle;
private TextView txtDescription;
private ImageButton btnChecking;
private WeakReference<IClickListenerAddRemove> listenerRef;
private boolean mIsPicked = false;
public RecyclerViewHolder(View root, IClickListenerAddRemove listener) {
super(root);
listenerRef = new WeakReference<>(listener);
txtTitle = root.findViewById(R.id.txtTitle);
txtDescription = root.findViewById(R.id.txtDescription);
btnChecking = root.findViewById(R.id.btnAction);
btnChecking.setOnClickListener(this);
}
public void setIsPicked(boolean mIsPicked) {
this.mIsPicked = mIsPicked;
}
public void setTitle(CharSequence text) {
txtTitle.setText(text);
}
public void setDescription(CharSequence text) {
txtDescription.setText(text);
}
public void setButtonDrawable(int drawableId) {
btnChecking.setImageResource(drawableId);
}
#Override
public void onClick(View v) {
if (v.getId() == btnChecking.getId()) {
if (!mIsPicked) {
btnChecking.setImageResource(R.drawable.ic_remove_24dp);
mIsPicked = true;
}
else {
btnChecking.setImageResource(R.drawable.ic_add_24dp);
mIsPicked = false;
}
listenerRef.get().onPositionClicked(getAdapterPosition(), mIsPicked);
}
}
}
Structure of this looks like this:
I have a JSON nested object and i have been trying to pass for example, stations "name" to next activity in the onClick method. 2 questions:
1) Have i set my model class right or is there a better way?
2) What steps am i missing to pass "name" from stations from the specific object clicked onto the next activity?
My error for code provided (
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
at com.example.ogure.trolleyproject.Adapter.StationsAdapter$ViewHolder.onClick(StationsAdapter.java:52)
Here is my JSON nested object
{
id: 1,
name: "Bus 1",
code: "TROL1",
tag_uid: "2HF4780H240827H40F284",
last_spotted_at: "2015-09-25 01:20:30",
last_spotted_station: 1,
stations: [
{
id: 1,
name: "Hennings Hall Station", //WHAT i want to pass
lat: "40.000000",
long: "41.000000",
_pivot_bus_id: 1,
_pivot_station_id: 1
}
}
Here is my model class
public class Bus implements Serializable {
#SerializedName("id")
private int mStationId;
#SerializedName("name")
private String mStationName;
#SerializedName("code")
private String mStationCode;
#SerializedName("tag_uid")
private String mStationTag_uid;
#SerializedName("last_spotted_at")
private String mStationLast_spot_time;
#SerializedName("last_spotted_station")
private int mStationLast_spot_station;
#SerializedName("stations")
private List<stations> stationInfo;
public int getmStationId() {
return mStationId;
}
public void setmStationId(int mStationId) {
this.mStationId = mStationId;
}
public List<stations> getStationInfo() {
return stationInfo;
}
public void setStationInfo(List<stations> stationInfo) {
this.stationInfo = stationInfo;
}
public int getmStationLast_spot_station() {
return mStationLast_spot_station;
}
public void setmStationLast_spot_station(int mStationLast_spot_station) {
this.mStationLast_spot_station = mStationLast_spot_station;
}
public String getmStationLast_spot_time() {
return mStationLast_spot_time;
}
public void setmStationLast_spot_time(String mStationLast_spot_time) {
this.mStationLast_spot_time = mStationLast_spot_time;
}
public String getmStationTag_uid() {
return mStationTag_uid;
}
public void setmStationTag_uid(String mStationTag_uid) {
this.mStationTag_uid = mStationTag_uid;
}
public String getmStationCode() {
return mStationCode;
}
public void setmStationCode(String mStationCode) {
this.mStationCode = mStationCode;
}
public String getmStationName() {
return mStationName;
}
public void setmStationName(String mStationName) {
this.mStationName = mStationName;
}
public class stations {
#SerializedName("id")
private int stationID;
#SerializedName("name")
private String stationName;
#SerializedName("lat")
private double stationLat;
#SerializedName("long")
private double stationLong;
#SerializedName("_pivot_bus_id")
private int mStationPiviotBusId;
#SerializedName("_pivot_station_id")
private int mStationPiviotStationId;
public int getmStationPiviotStationId() {
return mStationPiviotStationId;
}
public void setmStationPiviotStationId(int mStationPiviotStationId) {
this.mStationPiviotStationId = mStationPiviotStationId;
}
public int getmStationPiviotBusId() {
return mStationPiviotBusId;
}
public void setmStationPiviotBusId(int mStationPiviotBusId) {
this.mStationPiviotBusId = mStationPiviotBusId;
}
public double getStationLong() {
return stationLong;
}
public void setStationLong(double stationLong) {
this.stationLong = stationLong;
}
public double getStationLat() {
return stationLat;
}
public void setStationLat(double stationLat) {
this.stationLat = stationLat;
}
public String getStationName() {
return stationName;
}
public void setStationName(String stationName) {
this.stationName = stationName;
}
public int getStationID() {
return stationID;
}
public void setStationID(int stationID) {
this.stationID = stationID;
}
}
}
Here is my adapter class
public class StationsAdapter extends RecyclerView.Adapter<StationsAdapter.ViewHolder> {
private static List<Bus> mStations;
private static List<Bus.stations> mBusStations;
public StationsAdapter(List<Bus> stations) {
mStations = stations;
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView TvStationName;
public ImageView IvImageView;
public CardView mCardView;
public ViewHolder(View itemView) {
super(itemView);
TvStationName = (TextView) itemView.findViewById(R.id.station_name);
IvImageView = (ImageView) itemView.findViewById(R.id.station_photo);
mCardView = (CardView) itemView.findViewById(R.id.cv);
mCardView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
Bus s = mStations.get(position);
Bus.stations og = mBusStations.get(position); //HERE
Intent i = new Intent(v.getContext(), StationActivity.class);
i.putExtra("station_name", og.getStationName()); //and HERE is my problem
v.getContext().startActivity(i);
}
}
#Override
public StationsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.rv_card_item, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(StationsAdapter.ViewHolder holder, int position) {
Bus stationPos = mStations.get(position);
holder.TvStationName.setText(stationPos.getmStationName());
holder.mCardView.setTag(position);
}
#Override
public int getItemCount() {
return mStations.size();
}
Change your code to following:
public StationsAdapter(List<Bus> stations) {
List<Bus.stations> busStations = new ArrayList<>();
for (Bus bus : stations) {
busStations.addAll(bus.getStationInfo());
}
}
Issue is that you don't assign nothing to your mBusStations variable, that's why NPE throws.
Btw, don't use that confusing naming. Im talking about stationInfo in your Bus class.
I have a problem to send data using putExtra (of the a Adapter Class to an new Activity). I think that my problem is in Parcelable, but I cannot find where there are the problem.
Follow my class for you understand better.
Consultorio.class
public class Consultorio implements Parcelable {
private String nome;
private int photo;
public Consultorio() {
}
* #param nome
* #param photo
public Consultorio( String nome, int Photo)) {
this.nome = nome;
this.photo = photo;
}
/**
* #return
*/
public String getNome() {
return nome;
}
/**
* #param nome
*/
public void setNome(String nome) {
this.nome = nome;
}
public int getPhoto() {
return photo;
}
public void setPhoto(int photo) {
this.photo = photo;
}
//PARCELABLE
public Consultorio(Parcel parcel){
setNome(parcel.readString());
setPhoto(parcel.readInt());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(photo);
dest.writeString(nome);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Consultorio>() {
#Override
public Consultorio createFromParcel(Parcel source) {
return new Consultorio(source);
}
#Override
public Consultorio[] newArray(int size) {
return new Consultorio[size];
}
};
public void readFromParcel(Parcel in) {
nome = in.readString();
photo = in.readInt();
}
}
Follow My Class Fragment (because I'm using TabLayout)
public class ClinicaMedicaFragment extends Fragment {
private List<Consultorio> consultorioList = new ArrayList<Consultorio>();
private ClinicaAdapter adapter;
private Toolbar toolbar;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.clinica_medica_fragment, container, false);
RecyclerView recyclerView = (RecyclerView) v.findViewById(R.id.clinica_recyclerView);
toolbar = (Toolbar) v.findViewById(R.id.tb_main);
GridLayoutManager manager = new GridLayoutManager(v.getContext(),
2, GridLayoutManager.VERTICAL, false);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return (position % 3 == 0 ? 2 : 1);
}
});
recyclerView.setLayoutManager(manager);
List<Consultorio> list = new ArrayList<Consultorio>();
Consultorio c0 = new Consultorio();
c0.setPhoto(R.mipmap.img1);
c0.setNome("Name 1");
Consultorio c1 = new Consultorio();
c1.setPhoto(R.mipmap.img2);
c1.setNome("Name 2");
Consultorio c2 = new Consultorio();
c2.setPhoto(R.mipmap.img3);
c2.setNome("Name 3");
list.add(c0);
list.add(c1);
list.add(c2);
consultorioList = list;
adapter = new ClinicaAdapter(list);
recyclerView.setAdapter(adapter);
return v;
}
Follow My CLASS Adapter (in this class I'm using putExtra for send datato an new Activity)
public class ClinicaAdapter extends RecyclerView.Adapter<ClinicaAdapter.ViewHolder>{
private List<Consultorio> consultorioList;
//protected Boolean isHomeList = false;
public ClinicaAdapter(List<Consultorio> data) {
consultorioList = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.clinica_medica_item, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Consultorio consultorio = consultorioList.get(position);
holder.imageViewPhoto.setImageResource(consultorio.getPhoto());
holder.imageViewPhoto.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Intent intent = new Intent(view.getContext(), ClinicaActivity.class);
intent.putExtra("consultorio", consultorio);
view.getContext().startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return consultorioList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageViewPhoto;
public ViewHolder(View itemView) {
super(itemView);
imageViewPhoto = (ImageView) itemView.findViewById(R.id.clinc_img);
}
}
Inmy Class Activity I pick up information by
Consultorio mConsultorio;
mConsultorio = getIntent().getParcelableExtra("consultorio");
The parcelable should maintain order of write and read members. Your writeToParcel method write int photo first and then string nome, but readFromParcel method read int photo secondly.
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(nome); // <- I changed nome firstly.
dest.writeInt(photo);
}
public void readFromParcel(Parcel in) {
nome = in.readString();
photo = in.readInt();
}
I strongly recommend you to find and install Android Pacelable Code Generator plugin in Android Studio. It will automatically generate Parcelable i/o of the class for you. After installing the plugin, just right click at the class name, and click "Generate..." > "Parcelable" menu.