I desire to update each item of a recycled view every second with a new value. But instead of viewing only all updated values, all viewHolders seems to be stacked.
My recyclerView is declared like this :
recyclerView = findViewById(R.id.recycle);
adapter = new ExampleAdapter();
LinearLayoutManager recyclerViewLayout = new LinearLayoutManager(this);
recyclerView.setLayoutManager(recyclerViewLayout);
recyclerView.setAdapter(adapter);
I update the list of the adapter like this :
ArrayList<Integer> newList = new ArrayList<Integer>(Arrays.asList(0,1,2,3,4,5,6,7,8,9));
private void addNewInt() {
for (int i=0;i<newList.size();i++) {
newList.set(i, newList.get(i) + 10);
}
adapter.updateList(newList);
}
And this is my Adapter :
public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ViewHolder> {
private ArrayList<Integer> list;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView txt;
public ViewHolder(View view) {
super(view);
txt = view.findViewById(R.id.txt);
}
}
public ExampleAdapter() {
this.list = new ArrayList<>();
}
#Override
public ExampleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View cellView = inflater.inflate(R.layout.raw_example, parent, false);
return new ViewHolder(cellView);
}
#Override
public void onBindViewHolder(#NonNull ExampleAdapter.ViewHolder holder, int position) {
if (!list.isEmpty()) {
Integer val = list.get(position);
holder.txt.setText(Integer.toString(val));
}
}
#Override
public int getItemCount() {
return list.size();
}
public void updateList(ArrayList<Integer> newList) {
list.clear();
list.addAll(newList);
notifyDataSetChanged();
}
}
The problem does not seem to be linked with recycling. I tried to add holder.setIsRecyclable(false) to force recreate a new viewHolder without any effect.
I tried also to play with the recyclerView.getRecycledViewPool().setMaxRecycledViews and recyclerView.setItemViewCacheSize() methods without any success.
I try to use notifyItemRangeChange() instead of using the notifyDataSetChanged(). Nothing better.
I also try to force to clear the recyclerview before adding the new elements like this :
list.clear();
notifyDataSetChanged();
list.addAll(newList);
notifyDataSetChanged();
The xml of my Activity is the following:
<?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="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp" >
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
What is wrong with my code?
Related
Hello I am struggling with this problem. I have a RecyclerView with checkboxes items which is nested in another RecyclerView. My problem is that I want all the checkbox to be unchecked when the user click in a button in the fragment. So how could I access the checkbox view holder from my fragment button? Thank you.
Please be comprehensive with the mistakes in my code I am beginner, self-taught and it is my first app. Any help would be really appreciated.
fragment_index_category_filter.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="4dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".Fragments.IndexCategoryFilterFragment">
<!-- TODO: Update blank fragment layout -->
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:gravity="center"
app:layout_constraintTop_toTopOf="parent"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/home_activity_tb"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
android:gravity="center"
android:layout_gravity="center"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<RelativeLayout
android:id="#+id/toolbar"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:id="#+id/close_filters"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
android:padding="0dp"
app:fabCustomSize="50dp"
app:icon="#drawable/cancel"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="32dp"
app:shapeAppearanceOverlay="#style/ShapeAppearanceOverlay.MyApp.Button.Circle" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/appBarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Category list"
android:textAllCaps="false"
android:textColor="#color/black"
android:textSize="24sp" />
<com.google.android.material.button.MaterialButton
android:id="#+id/save_filters"
app:icon="#drawable/ic_check_ok"
app:iconSize="32dp"
app:iconGravity="textStart"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="0dp"
app:iconPadding="0dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:insetBottom="0dp"
app:shapeAppearanceOverlay="#style/ShapeAppearanceOverlay.MyApp.Button.Circle"
app:fabCustomSize="50dp"
/>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#+id/appBarLayout"
android:id="#+id/shortcuts_filter">
<com.google.android.material.button.MaterialButton
android:id="#+id/clear_filters"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:padding="0dp"
android:text="Clear all"
android:textAllCaps="false"
android:textSize="12sp" />
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="0dp"
android:id="#+id/select_all_filters"
android:textSize="12sp"
android:text="Select all"
android:layout_alignParentEnd="true"
android:textAllCaps="false"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"/>
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_margin="8dp"
app:layout_constraintTop_toBottomOf="#+id/shortcuts_filter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/categorySection_rv"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:orientation="vertical"/>
</androidx.constraintlayout.widget.ConstraintLayout>
IndexCategoryFilterFragment.java
public class IndexCategoryFilterFragment extends Fragment {
//Initialize variable
List<String> streamFiltersList;
RecyclerView categorySection_rv;
FirebaseDatabase firebaseDatabase;
DatabaseReference dbCategoryReference;
StreamFilterManager streamFilterManager;
MaterialButton save_filters, clear_filters, close_fragment;
FiltersViewModel filtersListObserver;
private FirebaseAuth mAuth;
FirebaseUser firebaseUser;
String userId;
SectionAdapter sectionAdapter;
List<Letter> letterList;
List<Category> categoryInLetter = new ArrayList<>();
public FilterInterface interfaceListener;
public IndexCategoryFilterFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container != null) {
container.removeAllViews();
}
// Inflate the layout for this fragment
mAuth = FirebaseAuth.getInstance();
firebaseUser = mAuth.getCurrentUser();
userId = firebaseUser.getUid();
View view = inflater.inflate(R.layout.fragment_index_category_filter, container, false);
save_filters = view.findViewById(R.id.save_filters);
categorySection_rv = view.findViewById(R.id.categorySection_rv);
clear_filters = view.findViewById(R.id.clear_filters);
close_fragment = view.findViewById(R.id.close_filters);
firebaseDatabase = FirebaseDatabase.getInstance();
dbCategoryReference = firebaseDatabase.getReference("CategoryIndexed");
save_filters.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
streamFilterManager.logOutFromUserSession();
streamFilterManager.writeListInPref(getContext(), streamFiltersList, userId);
Log.d("streamFilter", "onClick: " + streamFiltersList);
filtersListObserver = new ViewModelProvider(requireActivity()).get(FiltersViewModel.class);
filtersListObserver.setFiltersList(streamFiltersList);
getParentFragmentManager().beginTransaction().replace(R.id.fragment_container, new Home(), "home").commit();
}
});
close_fragment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getParentFragmentManager().popBackStack();
}
});
letterList = new ArrayList<>();
categoryInLetter = new ArrayList<>();
sectionAdapter = new SectionAdapter(getContext(), letterList);
categorySection_rv.setAdapter(sectionAdapter);
firebaseCategoryIndex();
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
streamFilterManager = new StreamFilterManager(getContext(), userId);
streamFiltersList = streamFilterManager.readFilterList(getContext(), userId);
if (streamFiltersList == null) {
streamFiltersList = new ArrayList<>();
}
clear_filters.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkboxUpdate();
}
});
}
private void firebaseCategoryIndex() {
// First recycler
Query queryLetter = dbCategoryReference.orderByChild("index");
queryLetter.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
letterList.clear();
for (DataSnapshot dsLetter : snapshot.getChildren()) {
Letter letter = dsLetter.getValue(Letter.class);
letterList.add(letter);
}
sectionAdapter.notifyDataSetChanged();
Log.d("letterList", "letterList: " + letterList.size());
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
// solutions testing
public interface FilterInterface {
void clearSelectAllFilters(Button allFilters);
}
private void checkboxUpdate() {
// 1. get ith item of the parent recyclerView
for(int i = 0 ; i< sectionAdapter.getItemCount();i++){
SectionAdapter.ViewHolder viewHolder = (SectionAdapter.ViewHolder) categorySection_rv.findViewHolderForAdapterPosition(i);
RecyclerView recyclerView = viewHolder.section_item_rv;
ItemSectionAdapter itemSectionAdapter = (ItemSectionAdapter) recyclerView.getAdapter();
itemSectionAdapter.update();
}
}
}
SectionAdapter.java
public class SectionAdapter extends RecyclerView.Adapter<SectionAdapter.ViewHolder> implements IndexCategoryFilterFragment.FilterInterface {
Context context ;
List<Letter> letterList;
DatabaseReference categoryListRef;
public SectionAdapter(Context context, List<Letter> letterList) {
this.context = context;
this.letterList = letterList;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.section_category,parent,false);
return new SectionAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
List<Category> letterCategoryList = new ArrayList<>();
Letter letter = letterList.get(position);
holder.section_letter.setText(letter.getIndex());
holder.section_title_ll.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int visible = holder.section_item_rv.getVisibility();
if (visible == View.VISIBLE){
holder.section_item_rv.setVisibility(View.GONE);
} else {
holder.section_item_rv.setVisibility(View.VISIBLE);
}
}
});
categoryListRef = FirebaseDatabase.getInstance().getReference("CategoryIndexed").child(letter.getIndex()).child("content");
ItemSectionAdapter itemSectionAdapter = new ItemSectionAdapter(letterCategoryList);
categoryListRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dsLetterContent : snapshot.getChildren()){
Category category = dsLetterContent.getValue(Category.class);
category.setCheckState(true);
Log.d("letterList", "letterList: "+ category.getCategoryName() + " "+ category.isCheckState());
letterCategoryList.add(category);
}
itemSectionAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
holder.section_item_rv.setAdapter(itemSectionAdapter);
}
#Override
public int getItemCount() {
return letterList.size();
}
#Override
public void clearSelectAllFilters(Button allFilters) {
}
public class ViewHolder extends RecyclerView.ViewHolder {
public MaterialTextView section_letter;
public RecyclerView section_item_rv;
public LinearLayout section_title_ll;
public ViewHolder(#NonNull View itemView) {
super(itemView);
section_letter = itemView.findViewById(R.id.section_letter);
section_item_rv = itemView.findViewById(R.id.section_item_rv);
section_title_ll = itemView.findViewById(R.id.section_title_ll);
}
}
}
ItemSectionAdpater.java
public class ItemSectionAdapter extends RecyclerView.Adapter<ItemSectionAdapter.ViewHolder> implements IndexCategoryFilterFragment.FilterInterface {
List<Category> categoryList;
public ItemSectionAdapter(List<Category> categoryList) {
this.categoryList = categoryList;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.index_category_name_item,parent,false);
return new ItemSectionAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Category category = categoryList.get(position);
holder.indexItemCategory.setText(category.getCategoryName());
holder.cb_categoryItem.setChecked(category.isCheckState());
}
#Override
public int getItemCount() {
return categoryList.size();
}
#Override
public void clearSelectAllFilters(Button allFilters) {
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView indexItemCategory;
public CheckBox cb_categoryItem;
public RelativeLayout category_item_rl;
public ViewHolder(#NonNull View itemView) {
super(itemView);
indexItemCategory = itemView.findViewById(R.id.indexItemCategory);
cb_categoryItem = itemView.findViewById(R.id.cb_categoryItem);
category_item_rl = itemView.findViewById(R.id.category_item_rl);
}
}
public void update() {
categoryList.forEach(category -> category.setCheckState(false));
notifyDataSetChanged();
}
}
Make a public method in adapter and then pass your new data with changed checked values to true, and then notify the adapter like shown below (or update the existing method with the code given below).
public void updateList(ArrayList<Category> categoryList) {
this.categoryList = categoryList;
notifyDataSetChanged();
}
then simply call this method wherever you need with the adapter object in your fragment.
I have been making an app that uses a recycler view in a fragment. how the contents of the recycler view have not been showing up. I am not sure what I have done wrong as the app does not crash when it is run. Please tell me what i need to do.
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"`enter code here`
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Fragments.Home_Fragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/cetagory_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorAccent"
android:elevation="3dp" />
</FrameLayout>
Home_Fragment.java
private RecyclerView categoryRecyclerView;
private CategoryAdapter categoryAdapter;
public Home_Fragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_home, container, false);
categoryRecyclerView = view.findViewById(R.id.cetagory_recyclerview);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
categoryRecyclerView.setLayoutManager(layoutManager);
List<CategoryModel> categoryModelList = new ArrayList<CategoryModel>();
categoryModelList.add(new CategoryModel("Link","Home"));
categoryModelList.add(new CategoryModel("Link","Electronicse"));
categoryModelList.add(new CategoryModel("Link","Garments"));
categoryModelList.add(new CategoryModel("Link","Fashion"));
categoryModelList.add(new CategoryModel("Link","Toys"));
categoryModelList.add(new CategoryModel("Link","Sporte"));
categoryModelList.add(new CategoryModel("Link","Furniture"));
categoryModelList.add(new CategoryModel("Link","Wall Art"));
categoryModelList.add(new CategoryModel("Link","Appliance"));
categoryAdapter = new CategoryAdapter(categoryModelList);
categoryRecyclerView.setAdapter(categoryAdapter);
categoryAdapter.notifyDataSetChanged();
return view;
}
CategoryModel.java
private String categoryItemIconLink;
private String categoryName;
public CategoryModel(String categoryItemIconLink, String categoryName) {
this.categoryItemIconLink = categoryItemIconLink;
this.categoryName = categoryName;
}
public String getCategoryItemIconLink() {
return categoryItemIconLink;
}
public void setCategoryItemIconLink(String categoryItemIconLink) {
this.categoryItemIconLink = categoryItemIconLink;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
CategoryAdapter.java
Context context;
private List<CategoryModel> categoryModelList = new ArrayList<CategoryModel>();
public CategoryAdapter(List<CategoryModel> categoryModerList) {
this.context = context;
this.categoryModelList = categoryModelList;
}
#NonNull
#Override
public CategoryAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.category_item, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull CategoryAdapter.ViewHolder holder, int position) {
String icon = categoryModelList.get(position).getCategoryItemIconLink();
String name = categoryModelList.get(position).getCategoryName();
holder.setCategoryName(name);
}
#Override
public int getItemCount() {
return categoryModelList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private ImageView categoryIcon;
private TextView categoryName;
public ViewHolder(#NonNull View itemView) {
super(itemView);
categoryIcon = itemView.findViewById(R.id.category_item_icon);
categoryName = itemView.findViewById(R.id.category_item_name);
}
private void setCategoryIcon() {
//Todo: set categoryIcone here
}
private void setCategoryName(String name) {
categoryName.setText(name);
}
}
You have not initialized your variables inside your adapter
Replace this...
public CategoryAdapter(List<CategoryModel> categoryModerList) {
this.context = context;
this.categoryModelList = categoryModelList;
}
With this..
public CategoryAdapter(Context context,List<CategoryModel> categoryModelList) {
this.context = context;
this.categoryModelList = categoryModelList;
}
then inside your fragment where you are calling adapters constructor add change this line.
from..
categoryAdapter = new CategoryAdapter(categoryModelList);
to..
categoryAdapter = new CategoryAdapter(getContext(),categoryModelList);
I am writing an app. that you can search info about celebs and save it to a SQlite database. I followed tutorials in showing the information but when I run the app it crashes without an error... please assist
When I request the data I only want the names display in a Listview, then when the user clicks on the name of the Celeb, it will open a page with all the saved data..I have no idea where to even start looking for the problem..I can open the app, save the data but when I open the activity to show the ListView it crashes without an error...
my xml for displaying the listview
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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="wrap_content"
android:background="#drawable/mway"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="#color/colorPrimaryDark"
android:text="#string/app_name"
android:textAlignment="center"
android:textColor="#color/colorPrimary"
android:textSize="32sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/list_view"
android:background="#drawable/mway">
</ListView>
</LinearLayout>
Here is my java file for displaying the listview
import android.database.Cursor;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
public class viewceleb extends AppCompatActivity {
DatabaseHelper db;
ArrayList<String> listItems;
ArrayAdapter adapter;
ListView userList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewceleb);
userList = findViewById(R.id.list_view);
listItems = new ArrayList<>();
viewData();
userList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int i, long id) {
String text = userList.getItemAtPosition(i).toString();
Toast.makeText(viewceleb.this, "Now something can happen", Toast.LENGTH_LONG).show();
}
});
}
private void viewData() {
Cursor cursor = db.viewData();
if (cursor.getCount()== 0){
Toast.makeText(this,"No Data To Show", Toast.LENGTH_LONG).show();
}else {
while(cursor.moveToNext()){
listItems.add(cursor.getString(1));//index 1 is name, 0 is ID
}
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listItems);
userList.setAdapter(adapter);
}
}
}
You are only declaring db, it needs to be instantiated.
That is you have DatabaseHelper db; and you additionall need db = new DatabaseHelper(?); where ? are the parameters required by the DatabaseHelper constructor. Typically just the Context so perhaps db = new DatabaseHelper(this);. This would be coded in the activity's onCreate method BEFORE calling the viewData method.
e.g.
public class viewceleb extends AppCompatActivity {
DatabaseHelper db;
ArrayList<String> listItems;
ArrayAdapter adapter;
ListView userList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewceleb);
dn = new DatabaseHelper(this); //<<<<<<<<<< ADDED note just the context has been assumed, the parameters depend upon the constructor as per what is coded in the DatabaseHelper class.
userList = findViewById(R.id.list_view);
listItems = new ArrayList<>();
viewData();
userList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int i, long id) {
String text = userList.getItemAtPosition(i).toString();
Toast.makeText(viewceleb.this, "Now something can happen", Toast.LENGTH_LONG).show();
}
});
}
private void viewData() {
Cursor cursor = db.viewData();
if (cursor.getCount()== 0){
Toast.makeText(this,"No Data To Show", Toast.LENGTH_LONG).show();
}else {
while(cursor.moveToNext()){
listItems.add(cursor.getString(1));//index 1 is name, 0 is ID
}
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listItems);
userList.setAdapter(adapter);
}
}
}
If I want to create a recycler view insider a recycler view in android, how to handle the view holder in the first container of recycler view and how to handle the transmission in two recycler view? Please give me some suggestion. Thank you very much.
Problem Statement : We have to display three items in parent recycler view. First two items are normal cardViews and the third item is child recycler view.
The top two items are card views and the third item is a list of hotels.
MainActivity.class :
public class **MainActivity** extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
ArrayList<DataModel> items = new ArrayList<>();
items.add(new DataModel("Bus"));
items.add(new DataModel("Flight"));
ArrayList<String> hotelsList=new ArrayList<>();
hotelsList.add("Hotel 1");
hotelsList.add("Hotel 2");
hotelsList.add("Hotel 2");
items.add(new DataModel("Hotels",hotelsList));
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
ParentAdapter parentAdapter = new ParentAdapter(items,MainActivity.this);
recyclerView.setAdapter(parentAdapter);
}
}
activity_main.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="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
DataModel.class
public class DataModel {
private String title;
private ArrayList<String> hotels;
public DataModel(String title){
this.title=title;
}
public DataModel(String title, ArrayList<String> hotels){
this.title=title;
this.hotels=hotels;
}
public String getTitle() {
return title;
}
public ArrayList<String> getHotels() {
return hotels;
}
}
ParentAdapter.class : Parent Recycler View
public class ParentAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<DataModel> items;
private Context mContext;
public ParentAdapter(ArrayList<DataModel> items, Context mContext) {
this.items = items;
this.mContext=mContext;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == ViewType.NORMAL_ITEM) {
return new NormalHolder(layoutInflater.inflate(R.layout.normal_view, parent, false));
} else if (viewType == ViewType.HOTELS_LIST_ITEM) {
return new ListHolder(layoutInflater.inflate(R.layout.list_view, parent, false));
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int cardType = getItemViewType(position);
switch (cardType) {
case ViewType.NORMAL_ITEM:
NormalHolder normalHolder=(NormalHolder) holder;
normalHolder.title.setText(items.get(position).getTitle());
break;
case ViewType.HOTELS_LIST_ITEM:
ListHolder listHolder=(ListHolder) holder;
HotelCardAdapter hotelCardAdapter = new HotelCardAdapter(mContext, items.get(position).getHotels());
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
listHolder.hotelsList.setLayoutManager(linearLayoutManager);
listHolder.hotelsList.setAdapter(hotelCardAdapter);
break;
}
}
private interface ViewType {
int NORMAL_ITEM = 0;
int HOTELS_LIST_ITEM = 1;
}
#Override
public int getItemViewType(int position) {
if (position == 0 || position == 1) {
return ViewType.NORMAL_ITEM;
} else return ViewType.HOTELS_LIST_ITEM;
}
#Override
public int getItemCount() {
return items.size();
}
private class NormalHolder extends RecyclerView.ViewHolder {
TextView title;
public NormalHolder(View inflate) {
super(inflate);
title=inflate.findViewById(R.id.title);
}
}
private class ListHolder extends RecyclerView.ViewHolder {
RecyclerView hotelsList;
public ListHolder(View inflate) {
super(inflate);
hotelsList = inflate.findViewById(R.id.hotel_list);
}
}
}
normal_view.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="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:padding="6dp">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bus"
android:textColor="#color/colorPrimary"
android:textSize="20sp"/>
<Button
android:id="#+id/view_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:gravity="center"
android:text="View All"
android:textSize="12sp"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
list_view.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="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp">
<TextView
android:id="#+id/header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hotels"
android:textColor="#color/colorPrimary"
android:textSize="17sp"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/hotel_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/header"
android:layout_marginTop="12dp"
android:orientation="horizontal"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
HotelCardAdapter.class : Child Recycler View
public class HotelCardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<String> hotelsObject;
private Context context;
public HotelCardAdapter(Context context, ArrayList<String> hotelsObject) {
this.hotelsObject = hotelsObject;
this.context = context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
return new HotelCarouselHolder(layoutInflater.inflate(R.layout.hotel_carousel_item, null));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
HotelCarouselHolder hotelCarouselHolder = (HotelCarouselHolder) holder;
hotelCarouselHolder.title.setText(hotelsObject.get(position));
}
#Override
public int getItemCount() {
return hotelsObject.size();
}
private class HotelCarouselHolder extends RecyclerView.ViewHolder {
private TextView title;
public HotelCarouselHolder(View inflate) {
super(inflate);
title = inflate.findViewById(R.id.title);
}
}
}
hotel_carousel_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="match_parent"
android:padding="16dp">
<RelativeLayout
android:id="#+id/hotel_details_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/hotel_image"
android:layout_width="256dp"
android:layout_height="144dp"
android:scaleType="centerCrop"
android:src="#999999"/>
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/hotel_image"
android:textSize="16sp"
android:text="Hotels 1"/>
</RelativeLayout>
</RelativeLayout>
Hope this helps!!
I added a Recyclerview in one item of RecyclerViewPager(https://github.com/lsjwzh/RecyclerViewPager).
And I want to scroll the RecyclerView when I touch on it.
I have tried :
View.OnTouchListener listener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_DOWN:
mRecyclerViewPager.requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mRecyclerViewPager.requestDisallowInterceptTouchEvent(false);
break;
}
return false;
}
};
mRecyclerView.setOnTouchListener(listener);
But I can only scroll the RecyclerView sometimes.
I think it can be sloved by implementing NestedScrollingParent in RecyclerViewPager or changing onTouchEvent in RecyclerViewPager .But I'm not familiar with them.
I followed the steps to configure and create the simple example using the Github documentation.
Main Activity XML
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
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.stackoverflow.recyclerviewstack.MainActivity">
<com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="1dp"
android:paddingRight="1dp"
app:rvp_triggerOffset="0.1"
app:rvp_singlePageFling="true"
android:clipToPadding="false"
/>
</RelativeLayout>
Main Activiy class
package com.stackoverflow.recyclerviewstack;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager;
public class MainActivity extends AppCompatActivity {
RecyclerAdapter mAdapter;
RecyclerViewPager mRecycler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecycler = (RecyclerViewPager) findViewById(R.id.list);
// setLayoutManager like normal RecyclerView, you do not need to change any thing.
LinearLayoutManager layout = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecycler.setLayoutManager(layout);
//set adapter
//You just need to implements ViewPageAdapter by yourself like a normal RecyclerView.Adpater.
mAdapter = new RecyclerAdapter(ItemListGenerator.generateCollection(15, "OutItem "));
mRecycler.setAdapter(mAdapter);
}
}
RecyclerAdapter
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
List<String> collection;
public RecyclerAdapter(List<String> collection) {
this.collection = collection;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView item;
RecyclerView mInnerRecycler;
public ViewHolder(View view) {
super(view);
item = (TextView) view.findViewById(R.id.title);
mInnerRecycler = (RecyclerView) view.findViewById(R.id.innerRecycler);
LinearLayoutManager layout = new LinearLayoutManager(view.getContext(),
LinearLayoutManager.HORIZONTAL, false);
mInnerRecycler.setLayoutManager(layout);
mInnerRecycler.setAdapter(new InnerAdapter());
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.outer_collection, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if(position < 0 || position > getItemCount()) return;
String itemString = collection.get(position);
holder.item.setText(itemString);
}
#Override
public int getItemCount() {
return collection.size();
}
}
the layout use by RecyclerViewPager to create ViewHolder
The ViewHolder use the layout outer_collection:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:layout_margin="2dip"
android:background="#color/colorPrimary"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/innerRecycler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
The InnerAdapter
public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.ViewHolder> {
List<String> collection;
public InnerAdapter() {
this.collection = ItemListGenerator.generateCollection(15, "Inner ");
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView item;
public ViewHolder(View itemView) {
super(itemView);
item = (TextView) itemView.findViewById(R.id.item);
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.simple_item, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if(position < 0 || position > getItemCount()) return;
holder.item.setText(collection.get(position));
}
#Override
public int getItemCount() {
return collection.size();
}
}
Tip
For the RecyclerViewPager I used this orientation:
LinearLayoutManager layout = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
And for the RecyclerView inside this one:
LinearLayoutManager layout = new LinearLayoutManager(view.getContext(), LinearLayoutManager.HORIZONTAL, false);
If you use VERTICAL in the PagerView you can navigate in the horizontal collection or change to HORIZONTAL the PagerView orientation and you can scroll your inside items in the VERTICAL orientation.
You have to evaluate how do you want to use it. I hope this code help with your problem and also to rethink your design. Maybe is not a good practice or UX use the same orientation for both containers. I am not a UX expert.
I will like to be more helpful.