I have implemented recycler view with data binding using a baseadapter which handles all the binding of any layout item.
I have tried to implement per item click listener using method reference and Listener bindings, but I couldn't do that.
Here is my code. Can you give me a sample which is the simple way to detect every single item of the recycler view and I want to add click listener for every single item for different purposes. Thanks.
MyBaseAdapter
public abstract class MyBaseAdapter extends RecyclerView.Adapter<MyBaseAdapter.MyViewHold> {
public class MyViewHold extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewDataBinding binding;
Context context;
public MyViewHold(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
context = binding.getRoot().getContext();
binding.getRoot().setOnClickListener(this);
}
// Here BR.pojo must be matched to layout variable name
//our layout variable was
/*
<variable
name="pojo"
type="com.durbinlabs.databinding.POJO"
/>
*/
public void bind(Object obj) {
binding.setVariable(BR.pojo, obj);
binding.setVariable(BR.food, obj);
binding.executePendingBindings();
}
#Override
public void onClick(View view) {
// for all view
}
}
#Override
public MyViewHold onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, getLayoutIdForType(viewType)
, parent, false);
return new MyBaseAdapter.MyViewHold(binding);
}
#Override
public void onBindViewHolder(MyViewHold holder, int position) {
holder.bind(getDataAtPosition(position));
Log.d("click", "" + holder.getItemId());
}
public abstract Object getDataAtPosition(int position);
public abstract int getLayoutIdForType(int viewType);}
my pojo class
public class POJO extends BaseObservable {
int img;
String name;
public POJO(int img) {
this.img = img;
}
public void setImg(int img) {
this.img = img;
}
public int getImg() {
return img;
}
public POJO(int img, String name) {
this.img = img;
this.name = name;
}
#Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}}
recycler view row layout (per item)
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="pojo"
type="com.durbinlabs.databinding.POJO" />
</data>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_marginRight="6dip"
android:contentDescription="TODO"
android:onClick="#{handlers::imgClick}"
android:src="#mipmap/ic_launcher" />
<TextView
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:layout_toRightOf="#id/icon"
android:ellipsize="marquee"
android:maxLines="1"
android:text="#{pojo.name}"
android:textColor="#android:color/black"
android:textSize="12sp" />
</RelativeLayout>
Adapter
public class Adapter extends MyBaseAdapter {
private List<POJO> itemList;
Context context;
public Adapter(List<POJO> itemList) {
this.itemList = itemList;
}
public Adapter(List<POJO> itemList, Context context) {
this.itemList = itemList;
this.context = context;
}
#Override
public Object getDataAtPosition(int position) {
return itemList.get(position);
}
#Override
public int getLayoutIdForType(int viewType) {
return R.layout.rowlayout;
}
#Override
public int getItemCount() {
return itemList.size();
}}
Try this in your adapter class not base adapter
holder.binding.getRoot().findViewById(R.id.icon).setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "clicked", Toast.LENGTH_SHORT).show();
}
}
);
Related
So, I have a recycler view and the items inside a recyclerview are dynamic. That is there can be one card or two cards. as you can see the recyclerview index 1 has only one item, whereas recyclerview index 0 has two cards. How can I achieve this?
You can do that using nested recylerview means reacyclerview insiderecyclerview.
You can follow the below way.
activity_main.xml
<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">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity implements YourInterface {
RecyclerView recyclerView;
private CategoryAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpRecyclerView();
// add your data to your arraylist and pass it to setInfoToAdapter method like below
ArrayList<CategoryItem> categoryItemList = new ArrayList<>();
categoryItemList.add(new CategoryItem("Item Title"))
categoryList.add(new Category("Section Title", categoryItemList));
setInfoToAdapter(categoryList );
}
//setup recycler view
private void setUpRecyclerView() {
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
private void setInfoToAdapter(List<Category> categoryList) {
adapter = new CategoryAdapter(this, categoryList, this); // here last parameters for your inteface
recyclerView.setAdapter(adapter);
}
#Override
public void doSomething(String title) {
// here you can do whatever you want it tigger when item adapter call this method.
}
}
CategoryAdapter.java
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.CategorySectionHolder> {
private Context context;
private List<Category> categoryList;
private YourInterface interface;
public CategoryAdapter(Context context, List<Category> categoryList,YourInterface interface) {
this.context = context;
this.categoryList = categoryList;
this.interface = interface; //
}
#Override
public CategorySectionHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.category_section_row, parent, false);
return new CategorySectionHolder(view);
}
#Override
public void onBindViewHolder(CategorySectionHolder holder, int position) {
final Category category = categoryList.get(position);
final String categoryName = category.getName();
holder.tvSectionLabel.setText(categoryName);
// data set for your items
final ArrayList<CategoryItem> itemList =category.getItems(); // here you got your item list for each category
// adapter for your items
final CategoryItemAdapter adapter;
adapter = new CategoryItemAdapter(context, itemList, interface);
//recycler view for items
holder.rvCategoryItems.setHasFixedSize(true);
holder.rvCategoryItems.setNestedScrollingEnabled(false);
holder.rvCategoryItems.setLayoutManager(new LinearLayoutManager(context));
holder.rvCategoryItems.setAdapter(adapter);
}
#Override
public int getItemCount() {
return categoryList.size();
}
public static class CategorySectionHolder extends RecyclerView.ViewHolder {
TextView tvSectionLabel;
RecyclerView rvCategoryItems;
public CategorySectionHolder(View itemView) {
super(itemView);
// initialize your views here
tvSectionLabel = itemView.findViewById(R.id.tvSectionLabel);
rvCategoryItems = itemView.findViewById(R.id.rvCategoryItem);
}
}
}
And category_section_row design for CategoryAdapter which have a recyclerview.
category_section_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="#dimen/_5sdp">
<TextView
android:id="#+id/tvSectionLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Label"
android:layout_alignParentLeft="true"
android:textStyle="bold"
android:textColor="#android:color/darker_gray"
android:textSize="#dimen/_14ssp" />
<!-- recycler view for items -->
<android.support.v7.widget.RecyclerView
android:id="#+id/rvCategoryItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/tvSectionLabel"
android:layout_marginTop="#dimen/_5sdp" />
</RelativeLayout>
And Adapter for items
CategoryItemAdapter.java
public class CategoryItemAdapter extends RecyclerView.Adapter<CategoryItemAdapter.CategoryItemsHolder> {
private Context context;
private List<CategoryItem> itemModels;
private YourInterface interface;
public CategoryItemAdapter(Context context, List<CategoryItem> itemModels,YourInterface interface) {
this.context = context;
this.itemModels = itemModels;
this.interface = interface;
}
#Override
public CategoryItemsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.category_item_row, parent, false);
return new CategoryItemsHolder(view);
}
#Override
public void onBindViewHolder(final CategoryItemsHolder holder, final int position) {
holder.itemName.setText(itemModels.get(position).getTitle());
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// here you can do whatever you want to click of item cardview.
// here you call method of your interface
interface.doSomething("Hello from item adapter")
}
});
}
#Override
public int getItemCount() {
return itemModels.size();
}
public static class CategoryItemsHolder extends RecyclerView.ViewHolder {
TextView itemName;
CardView cardView
public CategoryItemsHolder(View itemView) {
super(itemView);
// initialize your views here.
itemName = itemView.findViewById(R.id.tvItemNameCategory);
cardView = itemView.findViewById(R.id.cardView);
}
}
}
category_item_row.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cardView"
app:cardBackgroundColor="#color/black"
app:cardCornerRadius="#dimen/_3sdp"
app:cardElevation="#dimen/_3sdp">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/tvItemNameCategory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:fontFamily="sans-serif"
android:padding="#dimen/_5sdp"
android:text="#string/app_name"
android:textColor="#color/white"
android:textSize="#dimen/_14ssp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--Your other view goes there-->
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
And finally, your Model class should be like the following.
Category.java
public class Category{
private String name;
private ArrayList<CategoryItems> items;
public Category(String name, ArrayList<CategoryItems> items) {
this.name = name;
this.items = items;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
public ArrayList<CategoryItems> getItems() {
return items;
}
public void setItems(ArrayList<CategoryItems> items) {
this.items= items;
}
public class CategoryItems{
private String title;
public Category(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title= title;
}
}
}
Update:
create an interface like that
interface YourInterface{
public void doSomething(String title); //here you can use parameters as you want
}
Now you have to implement this interface in YourActivit in this case in MainActivity.
And pass instance of MainActivity to CategoryAdapter then CategoryItemAdapter. see these classes I have updated.
In Recycler adaptre in onCreateViewHolder add if else or switch case for multiple ui layouts
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == LAYOUT_TYPE_ONE) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type_one, parent, false);
return new FeedViewHolder(layoutView);
} else {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type_two, parent, false);
return new FeedViewHolder(layoutView);
}
}
you can use notifyDataSetChange(); on your adapter to update recycler every
Here, I have two recyclerview that has parentRecyclerViewAdapter and childRecyclerViewAdapter. Parent adapter has LinearLayoutManager.VERTICAL layout manager whereas Clild adapter has GridLayoutManager(mContext, 2) layout manager with itemDecoration.
When scrolling for the first time the RecyclerView scrolling is laggy and once the data is viewed the scrolling is smooth. Until the app instance is not completely removed the scrolling will be smooth and when the app reinitiate the scrolling is laggy again.
Please help me out to figure out this BUG!!
ParentRecyclerViewAdapter
public class RecyclerViewDataAdapter extends RecyclerView.Adapter<RecyclerViewDataAdapter.ItemRowHolder> {
private ArrayList<SectionDataModel> dataList;
private Context mContext;
private RecyclerListItemClick onListClick;
public RecyclerViewDataAdapter(Context context, ArrayList<SectionDataModel> dataList) {
this.dataList = dataList;
this.mContext = context;
onListClick = (RecyclerListItemClick) context;
}
#Override
public ItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return new ItemRowHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_row_template_section, null));
}
#Override
public void onBindViewHolder(ItemRowHolder itemRowHolder, int i) {
ArrayList<SingleTemplateModel> templateModelArrayList = dataList.get(i).getTemplateModelArrayList();
String sectionName = dataList.get(i).getHeaderTitle();
itemRowHolder.itemTitle.setText(sectionName);
TemplateChooserAdapter itemListDataAdapter = new TemplateChooserAdapter(mContext, templateModelArrayList , dataList.get(i).getHeaderTitle());
itemRowHolder.recycler_view_list.setAdapter(itemListDataAdapter);
}
#Override
public int getItemCount() {
return (null != dataList ? dataList.size() : 0);
}
public class ItemRowHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView itemTitle;
private RecyclerView recycler_view_list;
private ItemRowHolder(View view) {
super(view);
this.itemTitle = view.findViewById(R.id.itemTitle);
this.recycler_view_list = view.findViewById(R.id.recycler_view_list);
this.recycler_view_list.setOnClickListener(this);
this.recycler_view_list.setHasFixedSize(true);
this.recycler_view_list.setLayoutManager(new GridLayoutManager(mContext, 2));
this.recycler_view_list.addItemDecoration(new SpacesItemDecoration(2 , 25 , false));
}
#Override
public void onClick(View v) {
onListClick.onRecyclerItemClicked(dataList.get(getAdapterPosition()).getHeaderTitle());
}
}
}
ChildRecyclerAdapter
public class TemplateChooserAdapter extends RecyclerView.Adapter<TemplateChooserAdapter.ViewHolder> {
private static final String TAG = TemplateChooserAdapter.class.getSimpleName();
private Context context;
private ArrayList<SingleTemplateModel> templateModelArrayList;
private OnTemplatesListClicked onListClick;
public TemplateChooserAdapter(Context context, ArrayList<SingleTemplateModel> templateModelArrayList, String sectionName) {
this.context = context;
this.templateModelArrayList = templateModelArrayList;
onListClick = (OnTemplatesListClicked) context;
AppUtils.showLog(TAG, "CorporateUserAdapter");
}
#Override
public TemplateChooserAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(
LayoutInflater.from(parent.getContext()).inflate(R.layout.single_row_template_chooser, parent, false)
);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.templateView.setImageResource(templateModelArrayList.get(position).getImage());
}
#Override
public int getItemCount() {
return templateModelArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView templateView;
public ViewHolder(View itemView) {
super(itemView);
templateView = itemView.findViewById(R.id.template_view);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
templateModelArrayList.get(getAdapterPosition()).setShowIndicator(true);
onListClick.onTemplateClick(templateModelArrayList.get(getAdapterPosition())); // TODO send model when item clicked
}
}
}
Activity.java
private void recyclerViewJob() {
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
RecyclerViewDataAdapter adapter = new RecyclerViewDataAdapter(this, allSampleData);
recyclerView.setAdapter(adapter);
}
SectionDataModel.java
public class SectionDataModel {
private String headerTitle;
private ArrayList<SingleTemplateModel> templateModelArrayList;
public SectionDataModel() {
}
public SectionDataModel(String headerTitle, ArrayList<SingleTemplateModel> templateModelArrayList) {
this.headerTitle = headerTitle;
this.templateModelArrayList = templateModelArrayList;
}
public String getHeaderTitle() {
return headerTitle;
}
public void setHeaderTitle(String headerTitle) {
this.headerTitle = headerTitle;
}
public ArrayList<SingleTemplateModel> getTemplateModelArrayList() {
return templateModelArrayList;
}
public void setTemplateModelArrayList(ArrayList<SingleTemplateModel> templateModelArrayList) {
this.templateModelArrayList = templateModelArrayList;
}
}
SingleTemplateModel.java
public class SingleTemplateModel {
private String title;
private String skuName;
private int image;
private boolean showIndicator;
public SingleTemplateModel(String title, String skuName, int image, boolean showIndicator) {
this.title = title;
this.skuName = skuName;
this.image = image;
this.showIndicator = showIndicator;
}
public String getSkuName() {
return skuName;
}
public void setSkuName(String skuName) {
this.skuName = skuName;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getImage() {
return image;
}
public void setImage(int image) {
this.image = image;
}
public boolean isShowIndicator() {
return showIndicator;
}
public void setShowIndicator(boolean showIndicator) {
this.showIndicator = showIndicator;
}
}
single_row_template_section.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="30dp"
android:clickable="true"
android:focusable="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/itemTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:text="Sample title"
android:textColor="#color/white"
android:textSize="20sp"
android:textStyle="bold"
android:paddingLeft="5dp"
android:paddingBottom="10dp"/>
</RelativeLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal" />
</LinearLayout>
single_row_template_chooser.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="280dp"
card_view:cardElevation="6dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/template_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="#mipmap/model_9" />
</RelativeLayout>
</android.support.v7.widget.CardView>
I think you can try to lazy load your images from resources. There are libraries like Picasso or Glide that will help you with that.
So it may look like this:
Picasso:
import com.squareup.picasso.Picasso;
...
public class TemplateChooserAdapter extends RecyclerView.Adapter<TemplateChooserAdapter.ViewHolder> {
...
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Picasso.with(holder.itemView.getContext()).load(templateModelArrayList.get(position).getImage()).into(holder.templateView);
}
...
}
I am implementing a Recycler View and its respective adapter using Android Data Binding. The problem is that in all the tutorials I have seen, they initialize the data of the adapter with a Collection of View model class, like this:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements View.OnClickListener {
private ArrayList<ViewModel> items;
public RecyclerViewAdapter(ArrayList<ViewModel> items) {
this.items = items;
}
.....
}
But the data I want to pass to the Recycler View is a Collection of records from my database:
private ArrayList<Record> items;
How can I do that??
Thanks in advance!
EDIT
li_item.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="report"
type="viewmodel.ReportVM"/>
</data>
....
<TextView
android:id="#+id/tv_report_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textSize="18sp"
android:paddingBottom="6dp"
android:text="#{report.name}"
tools:text="Report 1"
/>
....
ADAPTER
public class ReportRVAdapter extends RecyclerView.Adapter<ReportRVAdapter.ReportViewHolder> {
private List<ReportDb> data;
public ReportRVAdapter(final List<ReportDb> reportData) {
this.data = reportData;
}
#Override
public ReportRVAdapter.ReportViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.li_item, parent, false);
return new ReportViewHolder(v);
}
#Override
public void onBindViewHolder(final ReportViewHolder holder, final int position) {
ReportDb item = data.get(position);
holder.getBinding().setVariable(BR.name, item.getName());
holder.getBinding().setVariable(BR.contractor, item.getContractor());
//make binding happen immediately
holder.getBinding().executePendingBindings();
}
#Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
public class ReportViewHolder extends RecyclerView.ViewHolder {
private ViewDataBinding binding;
public ReportViewHolder(final View rowView) {
super(rowView);
binding = DataBindingUtil.bind(rowView);
}
public ViewDataBinding getBinding() {
return binding;
}
}
}
MODEL VIEW
public class ReportVM extends BaseObservable {
public String name;
public String contractor;
public ReportVM() {
}
#Bindable
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
#Bindable
public String getContractor() {
return contractor;
}
public void setContractor(final String contractor) {
this.contractor = contractor;
}
}
You can use any collection in RecyclerView, It depends on you how you bind value with the View(TextView, ImageView).
Example:-
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
holder.txtHeader.setText(mDataset.get(position));
}
in above example, it depends on you, if you use Map then you need to get value using key. For set same get method can be used.
Finally I did realized that instead of:
holder.getBinding().setVariable(BR.name, item.getName());
holder.getBinding().setVariable(BR.contractor, item.getContractor());
//make binding happen immediately
holder.getBinding().executePendingBindings();
I should write this:
holder.getBinding().setReport(new ReportVM(item));
and my POJO:
private ReportDb report;
public ReportVM(final ReportDb report) {
this.report = report;
}
public String getName() {
return report.getName();
}
public String getContractor() {
return report.getContractor();
}
I tried databinding with RecyclerView, but my main_activity doesn't show the RecyclerView Content for my Objects. I dont know where the point of failure is.
Thanks for any advice.
Here my simple Code
class: User
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class: UserAdapter
public class UserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Activity host;
private ArrayList<User> items;
public UserAdapter(Activity activity, ArrayList<User> items) {
this.host = activity;
this.items = items;
Log.i("UserAdapterName", items.get(0).getName().toString()); //log shows Gordon
}
#Override
public UserAdapter.ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// inflate layout and retrieve binding
ListItemsBinding binding = DataBindingUtil.inflate(host.getLayoutInflater(),
R.layout.list_items, parent, false);;
return new ItemViewHolder(binding);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
User item = items.get(position);
ItemViewHolder itemViewHolder = (ItemViewHolder)holder;
itemViewHolder.bindItem(item);
}
#Override
public int getItemCount() {
return items.size();
}
static class ItemViewHolder extends RecyclerView.ViewHolder {
ListItemsBinding binding;
ItemViewHolder(ListItemsBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
void bindItem(User item) {
binding.setUser(item);
binding.executePendingBindings();
}
}
}
class: MainActivity
public class MainActivity extends AppCompatActivity {
private ArrayList<User> userList = new ArrayList<User>();
private ActivityMainBinding binding;
private UserAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
fillData();
adapter = new UserAdapter(MainActivity.this,userList);
binding.recycler.setAdapter(adapter);
}
private void fillData() {
userList.add(new User("Gordon", 26));
userList.add(new User("Dick", 34));
userList.add(new User("Ivan",20));
}
}
layout: activity_main
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Activity Text"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
layout: list_items
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="user"
type="de.bp2go.recgo.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.name}"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#android:color/black"
tools:text="Name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.age}"
android:textColor="#android:color/black"
tools:text="Age" />
</LinearLayout>
</layout>
For me it looks like You forgot to set proper LayoutManager for RecyclerView.
Missing line for vertical list:
binding.recycler.setLayoutManager(new LinearLayoutManager(this));
public class MainActivity extends AppCompatActivity {
private ArrayList<User> userList = new ArrayList<User>();
private ActivityMainBinding binding;
private UserAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fillData();
recycler = (RecyclerView) findViewById(R.id.recycler);
LinearLayoutManager manager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
recycler.setLayoutManager(manager);
adapter = new UserAdapter(MainActivity.this,userList);
recycler.setAdapter(adapter);
}
private void fillData() {
userList.add(new User("Gordon", 26));
userList.add(new User("Dick", 34));
userList.add(new User("Ivan",20));
}
}
public class UserAdapter extends RecyclerView.Adapter<ItemViewHolder.ViewHolder> {
private Activity host;
private ArrayList<User> items;
LayoutInflater inflator;
public UserAdapter(Activity activity, ArrayList<User> items) {
this.host = activity;
this.items = items;
Log.i("UserAdapterName", items.get(0).getName().toString()); //log shows Gordon
inflator=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public UserAdapter.ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// inflate layout and retrieve binding
View view =inflator.inflate(R.layout.list_items, parent,false);
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
User item = items.get(position);
ItemViewHolder itemViewHolder = (ItemViewHolder)holder;
itemViewHolder.bindItem(item);
}
#Override
public int getItemCount() {
return items.size();
}
static class ItemViewHolder extends RecyclerView.ViewHolder {
ListItemsBinding binding;
ItemViewHolder(ListItemsBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
void bindItem(User item) {
binding.setUser(item);
binding.executePendingBindings();
}
}
}
I have a recyclerview which populates data from SQL database. Now each row in the recyclerview has a seekbar which when moved displays it's progress in a textview inside the same row. The problem is when I scroll the recyclerview up or down then return back to the first changed row, the seekbar is returned to its default position. How can I make it save the new position ? In normal activities/fragments I use lifecycle methods as "onPause" to save/restore the state. Here we have onAttachedToRecyclerView, I think it should solve my problem but I don't know exactly how.
EDIT : here is a full simple app files which I'm working on to test this problem.
MainActivity.class
public class MainActivity extends AppCompatActivity {
private List<Score> scoreList = new ArrayList<>();
private RecyclerView recyclerView;
private MyAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mAdapter = new MyAdapter(scoreList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
prepareScoreData();
}
private void prepareScoreData() {
Score score = new Score("title", 5);
scoreList.add(score);
for(int i= 0; i<1000; i++){
score = new Score("title", 5);
scoreList.add(score);
}
mAdapter.notifyDataSetChanged();
}
}
MyAdapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Score> scoresList;
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView title, scoreView;
SeekBar seekbar;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
scoreView = (TextView) view.findViewById(R.id.score);
seekbar = (SeekBar) view.findViewById(R.id.seekbar);
}
}
public MyAdapter(List<Score> scoresList) {
this.scoresList = scoresList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final Score score = scoresList.get(position);
holder.title.setText(score.getTitle());
if (!score.getProgressed()) {
holder.seekbar.setProgress(0) ;
} else {
holder.seekbar.setProgress(score.getSeekbarProgress());
}
holder.seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
holder.scoreView.setText(String.valueOf(i));
score.setSeekbarProgress(i);
score.setProgressed(true);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
#Override
public int getItemCount() {
return scoresList.size();
}
}
Score class
public class Score {
private String title;
int seekbarProgress;
boolean progressed;
public Score() {
}
public Score(String title,int seekbarProgress) {
this.title = title;
this.seekbarProgress = seekbarProgress;
}
public void setProgressed(boolean progressed) {
this.progressed = progressed;
}
public void setTitle(String title) {
this.title = title;
}
public void setSeekbarProgress(int seekbarProgress) {
this.seekbarProgress = seekbarProgress;
}
public String getTitle() {
return title;
}
public int getSeekbarProgress() {
return seekbarProgress;
}
public boolean getProgressed() {
return progressed;
}
}
MainActivity_Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.moaness.tut_recyclerview.MainActivity">
<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="60dp"
android:paddingBottom="60dp"
android:layout_marginBottom="10dp"
android:clickable="true"
android:background="#f2f2f2"
android:orientation="vertical">
<TextView
android:id="#+id/title"
android:text="title"
android:textColor="#color/title"
android:textSize="16dp"
android:paddingTop="16dp"
android:textStyle="bold"
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/score"
android:text="score"
android:layout_below="#+id/title"
android:textSize="16dp"
android:paddingBottom="16dp"
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/score"
android:id="#+id/seekbar"
/>
</RelativeLayout>
If you are using recyclerview you need to maintain states of each row, means if you are checking using a condition(i.e. if) at any stage of recyclerview item(in recyclerview adapter class) then you need to handle else as well. I can send you a code snippet so you can have a good idea for recyclerview adapter.
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {
List<ViewHolder> holders = new ArrayList<ViewHolder>();
private ArrayList<ContactModel> arrayList = new ArrayList<>();
private Context context;
private LayoutInflater inflater;
public void clearAdapter() {
arrayList.clear();
notifyDataSetChanged();
}
public ContactsAdapter(Context context, ArrayList<ContactModel> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
public void setList(ArrayList<ContactModel> listSearch) {
this.arrayList = listSearch;
notifyItemRangeChanged(0, listSearch.size());
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.custom_row_for_contacts, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
holders.add(viewHolder);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final ContactModel current = this.arrayList.get(position);
holder.txtDriverName.setText(current.getName());
holder.txtDriverPhone.setText(current.getPhone());
if (current.getImgUrl().length() > 0) {
String urlLicenceThumb = UrlEndPoints.parentUrl + current.getImgUrl();
Glide.with(context).load(urlLicenceThumb).error(R.mipmap.ic_launcher).into(holder.imgDriver);
} else {
Glide.with(context).load(R.mipmap.ic_launcher).into(holder.imgDriver);
}
}
public void delete(int position) {
arrayList.remove(position);
notifyItemRemoved(position);
}
#Override
public int getItemCount() {
return (null != arrayList ? arrayList.size() : 0);
}
class ViewHolder extends RecyclerView.ViewHolder {
private TextView txtDriverName, txtDriverPhone;
private CircleImageView imgDriver;
private Button btnInvite;
private CheckBox chkAdd;
public ViewHolder(View itemView) {
super(itemView);
chkAdd = (CheckBox) itemView.findViewById(R.id.chkAdd);
imgDriver = (CircleImageView) itemView.findViewById(R.id.imgDriver);
txtDriverName = (TextView)itemView.findViewById(R.id.txtDriverName);
txtDriverPhone = (TextView) itemView.findViewById(R.id.txtDriverPhone);
btnInvite = (Button) itemView.findViewById(R.id.btnInvite);
}
}
}