I am trying to create a cardView with recyclerView with creating the CardView programmatically, here is my code, if it is not possible please let me know to use XML
onCreate of the main class
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.lesson_layout, container, false);
ExampleRecyclerView = (RecyclerView) rootView.findViewById(R.id.ExampleRecyclerView);
List<ViewExample> exampleList = new ArrayList<>();
Log.i("dddddd", String.valueOf(exampleList));
//alos the list just show [] in the Logs
adapter = new ExampleAdapter(this, exampleList);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
llm.setSmoothScrollbarEnabled(true);
ExampleRecyclerView.setScrollbarFadingEnabled(true);
ExampleRecyclerView.setLayoutManager(llm);
ExampleRecyclerView.setAdapter(adapter);
return rootView;
}
the ViewExample class
public class ViewExample {
private String StepHeader, Code, Explanation;
public ViewExample(String stepHeader, String code, String explanation) {
StepHeader = stepHeader;
Code = code;
Explanation = explanation;
}
Getters & Setters are here...
}
And the Adapter
public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleHolder> {
CardView ExampleCV;
List<ViewExample> exampleList;
ViewLesson viewLesson;
public ExampleAdapter(ViewLesson viewLesson, List<ViewExample> exampleList) {
this.viewLesson = viewLesson;
this.exampleList = exampleList;
}
public class ExampleHolder extends RecyclerView.ViewHolder { // here is where you define what text have value
LinearLayout parentL;
public ExampleHolder(View itemView) {
super(itemView);
parentL = new LinearLayout(parentL.getContext());
ExampleCV = new CardView(ExampleCV.getContext());
ExampleCV.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
parentL.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
parentL.setOrientation(LinearLayout.VERTICAL);
ExampleCV.addView(parentL);
}
}
#Override
public ExampleHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ExampleHolder(ExampleCV);
}
#Override
public void onBindViewHolder(final ExampleHolder holder, int position) {
TextView tv = null;
final TextView finalTv = tv;
RootRef.child("Development").child("Level 2").child("Intent").child("Putextra").child("Examples")
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.i("isa 5air", String.valueOf(dataSnapshot.getValue()));
finalTv.setText(String.valueOf(dataSnapshot.getValue()));
holder.parentL.addView(finalTv);
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
#Override
public int getItemCount() {
return 0;
}
}
Edit
NB : I have noticed that the code doesn't enter onBindViewHolder as I put test Log in it it doesn't print out
you can use in your lesson_layout with cardview as given below cardview can only one child you can use another container layout such linear or relative as you need
<android.support.v7.widget.CardView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
............some other views.....
</LinearLayout>
</android.support.v7.widget.CardView>
In your code, it seems that you are passing empty list to RecyclerView Adapter
List<ViewExample> exampleList = new ArrayList<>();
Log.i("dddddd", String.valueOf(exampleList));
//alos the list just show [] in the Logs
adapter = new ExampleAdapter(this, exampleList);
Suggested changes:
1.You can Add some elements in it before passing to the adapter or add element in list and then call
adapter.notifyDataSetChanged();
2.In your ExampleAdapter change getItemCount() method with bellow
#Override
public int getItemCount() {
return exampleList.size();
}
Edit:
3.Change your onCreateViewHolder()
#Override
public ExampleHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ExampleCV = new CardView(ExampleCV.getContext());
ExampleCV.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
return new ExampleHolder(ExampleCV);
}
4.Constructor of ExampleHolder with:
public ExampleHolder(View itemView) {
super(itemView);
parentL = new LinearLayout(parentL.getContext());
parentL.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
parentL.setOrientation(LinearLayout.VERTICAL);
itemView.addView(parentL);
}
Related
I`ve followed a tutorial to create a recyclerview for my app
I doesnt work, in that it only occasionally shows anything in the view
There doesnt appear to be any rime or reason at all...
The layout that is recycled
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="80dp">
<TextView
android:id="#+id/text_value"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="Test"
android:textColor="#000000"
android:textSize="18sp" />
</LinearLayout>
The xml with the recyclerview in it
<?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">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recycler_view_accounts"/>
</LinearLayout>
The RecyclerViewAdapter class
public class RecyclerViewAdapterAccounts extends RecyclerView.Adapter<RecyclerViewAdapterAccounts.ViewHolder> {
private ArrayList<String> mlist;
private Context mContext;
public RecyclerViewAdapterAccounts(ArrayList<String> list, Context context) {
mlist = list;
mContext = context;
}
#NonNull
#Override
public RecyclerViewAdapterAccounts.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerViewAdapterAccounts.ViewHolder holder, final int position) {
holder.accountName.setText(mlist.get(position));
holder.parent_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, mlist.get(position), Toast.LENGTH_LONG).show();
}
});
}
#Override
public int getItemCount() {
return mlist.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView accountName;
LinearLayout parent_layout;
public ViewHolder(#NonNull View itemView) {
super(itemView);
accountName = itemView.findViewById(R.id.text_value);
parent_layout = itemView.findViewById(R.id.parent_layout);
}
}
}
The relevant onCreate activity
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_accounts);
initAccounts();
RecyclerView recyclerView = findViewById(R.id.recycler_view_accounts);
RecyclerViewAdapterAccounts adapter = new RecyclerViewAdapterAccounts(accounts, this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter.notifyDataSetChanged();
}
Although not shown, I can test that initAccounts() is filling the array as it should
I can also see that onCreateViewHolder and onBindViewHolder is not being called
Any suggestions???
edit:
heres the initAccounts
private void initAccounts() {
DatabaseReference userRef =
FirebaseDatabase.getInstance().getReference().child("users");
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
Iterator<DataSnapshot> children = snapshot.getChildren().iterator();
while (children.hasNext()) {
DataSnapshot child = children.next();
String[] parts = child.getValue().toString().split(",");
String role = parts[0].replace('{', ' ');
String msg = child.getKey() + ": " + role;
accounts.add(msg);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The problem here is you are adding object to accounts but not notifying the Adapter about the change . Make the following changes to your code .
For setting adapter inside onCreate() use Only .
private RecyclerViewAdapterAccounts adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_accounts);
initAccounts();
RecyclerView recyclerView = findViewById(R.id.recycler_view_accounts);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new RecyclerViewAdapterAccounts(accounts, this);
recyclerView.setAdapter(adapter);
}
Now create a method in RecyclerViewAdapterAccounts to add elements in adapter ;
public void addAll(ArratList<String> list){
mlist.clear();// To clear list if thats the case
mlist.addAll(list);
notifyDataSetChanged();
}
Now you can add all elements in one go to adapter .
public void onDataChange(#NonNull DataSnapshot snapshot) {
ArrayList<String> dataList=new ArrayList<>();
Iterator<DataSnapshot> children = snapshot.getChildren().iterator();
while (children.hasNext()) {
DataSnapshot child = children.next();
String[] parts = child.getValue().toString().split(",");
String role = parts[0].replace('{', ' ');
String msg = child.getKey() + ": " + role;
dataList.add(msg);
}
adapter.addAll(dataList);
}
I want to display "No upcoming Appointments" when my recyclerview is empty and display recyclerview when it's not empty. I have tried various codes to check whether my recyclerview is empty or not, but none worked.
Here is my code
public class appointments extends Fragment {
private RecyclerView recyclerView;
private DatabaseReference ref;
private ArrayList<BookedUserInfo> arrayList;
private FirebaseRecyclerOptions<BookedUserInfo> options;
private FirebaseAuth mAuth;
private String uid;
private FirebaseRecyclerAdapter<BookedUserInfo, FireBaseViewHolderUpcomingAppointment> adapter;
private String shopname;
private ProgressDialog progressDialog;
private TextView emptyview;
private int x=0;
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View RootView = inflater.inflate(R.layout.appointment_navigation,container,false);
//find view by ID
recyclerView = (RecyclerView) RootView.findViewById(R.id.recycleupcomingappointment);
emptyview = (TextView) RootView.findViewById(R.id.empty_view);
//Auth instance
mAuth = FirebaseAuth.getInstance();
FirebaseUser currentuser = mAuth.getCurrentUser();
uid = currentuser.getUid();
//initialize progress dialog
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Loading");
progressDialog.show();
//database refrence
ref = FirebaseDatabase.getInstance().getReference().child("USER").child(uid).child("UpcomingAppointment");
ref.keepSynced(true);
//recycler view
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
llm.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(llm);
//array list
arrayList = new ArrayList<BookedUserInfo>();
options = new FirebaseRecyclerOptions.Builder<BookedUserInfo>().setQuery(ref,BookedUserInfo.class).build();
//adapter
adapter = new FirebaseRecyclerAdapter<BookedUserInfo, FireBaseViewHolderUpcomingAppointment>(options) {
#Override
protected void onBindViewHolder(#NonNull final FireBaseViewHolderUpcomingAppointment holder, int position, #NonNull final BookedUserInfo model) {
final String datedata = model.getDate();
final String timedata = model.getTime();
final int bookingiddata = model.getBookingid();
Date initDate = null;
try {
initDate = new SimpleDateFormat("dd-MM-yyyy").parse(datedata);
} catch (ParseException e) {
e.printStackTrace();
}
SimpleDateFormat formatter = new SimpleDateFormat("EEE, d MMM yyyy");
final String parsedDate = formatter.format(initDate);
holder.time.setText(timedata);
holder.date.setText(parsedDate);
holder.id.setText(String.valueOf(bookingiddata));
final String shopuid = model.getShopuid();
DatabaseReference myRef =FirebaseDatabase.getInstance().getReference().child("SHOP").child(shopuid);
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
shopname = dataSnapshot.child("shopname").getValue().toString();
holder.name.setText(shopname);
progressDialog.dismiss();
}
#Override
public void onCancelled(DatabaseError error) {
progressDialog.dismiss();
// Failed to read value
}
});
progressDialog.dismiss();
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), AppointmentBill.class);
intent.putExtra("bookingid",String.valueOf(bookingiddata));
intent.putExtra("timetext",timedata);
intent.putExtra("datetext",datedata);
intent.putExtra("uidtext",shopuid);
intent.putExtra("appointmentinfotext",model.getAppointmentinfo());
startActivity(intent);
}
});
}
#NonNull
#Override
public FireBaseViewHolderUpcomingAppointment onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new FireBaseViewHolderUpcomingAppointment(LayoutInflater.from(getActivity()).inflate(R.layout.cardview_appointment,parent,false));
}
};
recyclerView.setAdapter(adapter);
//check total items
if(adapter.getItemCount() == 0)
{
recyclerView.setVisibility(View.GONE);
emptyview.setVisibility(View.VISIBLE);
}
else
{
recyclerView.setVisibility(View.VISIBLE);
emptyview.setVisibility(View.GONE);
}
progressDialog.dismiss();
return RootView;
}
XML code
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/relativelayoutview"
android:layout_below="#id/upcomingappointments">
<TextView
android:id="#+id/empty_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="30dp"
android:visibility="gone"
android:background="#E7E7E7"
android:paddingBottom="30dp"
android:text="---------No Upcoming Appointments---------"
android:gravity="center">
</TextView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycleupcomingappointment"
android:layout_width="match_parent"
android:background="#E7E7E7"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
I'm using google firebase(realtime database) to get appointment details. Please suggest me a solution for this problem.
I also tried this but failed so I instead used snapshot.getchilderncount In my firebase database reference and checked if childrencount =0 or not
Create a value event listener For your apointment database reference and in it say if(snapshot.getChildrenCount==0) { ///your logic }
Try to move this logic inside onDataChange callback method:
//check total items
if(adapter.getItemCount() == 0)
{
recyclerView.setVisibility(View.GONE);
emptyview.setVisibility(View.VISIBLE);
}
else
{
recyclerView.setVisibility(View.VISIBLE);
emptyview.setVisibility(View.GONE);
}
this is a sample recyclerView app
Adapter.java
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
List<?> list; //i don`t know your model or type date then i write (?)
public Adapter(List<?> list) {
this.list = list;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.your_layout,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
//you write your code when bind your view hoder
YourMode model = list.get(position);
}
#Override
public int getItemCount() {
return list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(#NonNull View itemView) {
super(itemView);
//for get your view or widget your use **itemView.findViewById()**
}
}
}
and this code for get Item count :
public class MyFragment extends Fragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.your_fragment_layout, container,false);
Adapter adapter = Adapter(yourList);
if (adapter.getItemCount() == 0){
}else {
}
return view;
}
}
I know there is other questions like this with answers but they don't help me...
So I have a Fragment, in this one I use Volley to get a JSON from a Web API. What I want to do is to "refresh" my recycler view with the data I get in my response.
I have tried to add a method in my adapter. But nothing append when I try to change my adapter in my Volley.onresponse() method.
There is my Fragment :
public class TicketsIncidentsFragment extends Fragment implements Response.ErrorListener, Response.Listener<String> {
RequestQueue queue;
StringRequest stringRequest;
ListView listView;
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
String url;
private TicketsIncidentsViewModel ticketsIncidentsViewModel;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
ticketsIncidentsViewModel =
ViewModelProviders.of(this).get(TicketsIncidentsViewModel.class);
View root = inflater.inflate(R.layout.fragment_ticketsincidents, container, false);
return root;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
RecyclerView recyclerView = (RecyclerView)getView().findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
layoutManager= new LinearLayoutManager(getActivity().getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
MyAdapterTI myAdapterTI=new MyAdapterTI();
recyclerView.setAdapter(myAdapterTI);
queue = Volley.newRequestQueue(getActivity().getApplicationContext());
url = "http://myip/select/ticketsI";
stringRequest = new StringRequest(GET, url, TicketsIncidentsFragment.this, TicketsIncidentsFragment.this);
queue.add(stringRequest);
}
#Override
public void onErrorResponse(VolleyError error) {
}
#Override
public void onResponse(String response) {
RecyclerView recyclerView = (RecyclerView)getView().findViewById(R.id.recyclerview);
Gson gsonTicketsIncidents = new Gson();
ResponseJson responseJson = new ResponseJson();
responseJson = (ResponseJson) gsonTicketsIncidents.fromJson(response, ResponseJson.class);
List<Object> listTicketsIncidents = responseJson.getResponse();
try {
JSONArray tis = new JSONArray(listTicketsIncidents.toArray());
ArrayList<String> date = new ArrayList<String>();
ArrayList<String> nomUser = new ArrayList<String>();
for (int i = 0 ; i< tis.length(); i++) {
JSONObject ticketIncident = tis.getJSONObject(i);
nomUser.add(ticketIncident.get("NOMUSER").toString());
date.add(ticketIncident.get("DateSAISIE").toString());
}
MyAdapterTI myAdapterTI=new MyAdapterTI();
myAdapterTI.getList(nomUser, date);
recyclerView.setAdapter(myAdapterTI);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
There is my adapter :
public class MyAdapterTI extends RecyclerView.Adapter<MyAdapterTI.MyViewHolder> {
private List<Pair<String, String>> TI;
public void getList(ArrayList<String> nomUser, ArrayList<String> date){
for(int i =0; i<nomUser.size();i++){
TI = Arrays.asList( Pair.create(nomUser.get(i), date.get(i)));
}
}
#NonNull
#Override
public MyAdapterTI.MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.list_cell_ti, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyAdapterTI.MyViewHolder holder, int position) {
Pair<String, String> pair = TI.get(position);
holder.display(pair);
}
#Override
public int getItemCount() {
return 0;
}
public class MyViewHolder extends RecyclerView.ViewHolder{
private TextView nomUser;
private TextView date;
private Pair<String, String> currentPair;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
nomUser=(TextView)itemView.findViewById(R.id.nomuser);
date=(TextView)itemView.findViewById(R.id.date);
itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
}
});
}
public void display(Pair<String, String> pair) {
currentPair=pair;
nomUser.setText(pair.first);
date.setText(pair.second);
}
}
}
And there is the layout :
<androidx.constraintlayout.widget.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">
<ListView
android:id="#+id/listview_TI"
android:layout_width="97dp"
android:layout_height="34dp"
android:layout_marginTop="24dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.917"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.976" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="409dp"
android:layout_height="680dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.039" />
</androidx.constraintlayout.widget.ConstraintLayout>
Thank's for you're help
UPDATE :
Now my MyAdapter.getList() looks like this :
public void getList(ArrayList<String> nomUser, ArrayList<String> date){
for(int i =1; i<nomUser.size();i++){
TI.add(Pair.create(nomUser.get(i), date.get(i)));
}
notifyDataSetChanged();
}
But nothing change yet.
Last UPDATE :
The problem has been solved.
It's a ridiculous mistake I've made in my Adapter.
I used to return 0 but the solution is this :
#Override
public int getItemCount() {
return TI.size();
}
just change
#Override
public int getItemCount() {
return 0;
}
to
#Override
public int getItemCount() {
if(TI == null)
return 0;
else
return TI.size;
}
private List<Pair<String, String>> TI = new ArrayList();
public void getList(ArrayList<String> nomUser, ArrayList<String> date){
for(int i =0; i<nomUser.size();i++){
TI.add(Pair.create(nomUser.get(i), date.get(i)));
}
notifyDataSetChanged();
}
layoutManager= new LinearLayoutManager(getActivity().getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
MyAdapterTI myAdapterTI=new MyAdapterTI(getActivity().getApplicationContext(),ThisIsYourList);
recyclerView.setAdapter(myAdapterTI);
Don't do this in response
MyAdapterTI myAdapterTI=new MyAdapterTI();
recyclerView.setAdapter(myAdapterTI);
myAdapterTI make this global variable
Only update your list and then
myAdapterTI.notifyDataSetChanged();
Or in your adapter, you can do
this.notifyDataSetChanged(); ////in getList
I am trying to implement multiple view or so called heterogeneous recyclerview using firebase realtime database. I found a example of heterogeneous recyclerview implementation on github.
I followed this to implement on firebase. But my code didn't work.
fragment_search.java (one of the fragment in my tabbed view) This is my fragment file which contains the main recyclerview which will hold multiple views
public class fragment_search extends Fragment {
RecyclerView recyclerViewSearch;
private static SingleSearchBannerModel singleSearchBannerModel;
private static SingleSearchType1Model singleSearchType1Model;
private static DatabaseReference databaseReference;
private List<Object> objects = new ArrayList<>();
private static SearchMainAdapter searchMainAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_search,null);
//Recycler view initialized and Properties Set.
recyclerViewSearch = view.findViewById(R.id.recyclerview_search);
recyclerViewSearch.setHasFixedSize(true);
recyclerViewSearch.setLayoutManager(new LinearLayoutManager(getContext()));
databaseReference = FirebaseDatabase.getInstance().getReference();
return view;
}
private List<Object> getObjects(){
objects.addAll(getBannerData());
objects.addAll(getType1Data());
return objects;
}
public static List<SingleSearchBannerModel> getBannerData(){
final List<SingleSearchBannerModel> singleSearchBannerModelList = new ArrayList<>();
databaseReference.child("Featured").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
singleSearchBannerModel = dataSnapshot.getValue(SingleSearchBannerModel.class);
singleSearchBannerModelList.add(singleSearchBannerModel);
searchMainAdapter.notifyDataSetChanged();
System.out.println("this is image in getBanner == "+singleSearchBannerModel.getImage());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return singleSearchBannerModelList;
}
public static List<SingleSearchType1Model> getType1Data(){
final List<SingleSearchType1Model> singleSearchType1ModelList = new ArrayList<>();
databaseReference.child("Featured").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
singleSearchType1Model = dataSnapshot.getValue(SingleSearchType1Model.class);
singleSearchType1ModelList.add(singleSearchType1Model);
searchMainAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return singleSearchType1ModelList;
}
#Override
public void onStart() {
super.onStart();
searchMainAdapter = new SearchMainAdapter(getContext(),getObjects());
System.out.println("this is getObject == "+getObjects());
System.out.println("this is getBanner == "+getBannerData());
System.out.println("this is getType1 == "+getType1Data());
recyclerViewSearch.setAdapter(searchMainAdapter);
}
}
fragment_home.xml this is the xml file of fragment which contains one recyclerview (My main recyclerview).
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_search"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
Model files
*I have two model files. Basically getter and setters *
SingleSearchBannerModel.java My firsts model file.
public class SingleSearchBannerModel {
String Image;
public SingleSearchBannerModel() {
}
public SingleSearchBannerModel(String image) {
Image = image;
}
public String getImage() {
return Image;
}
public void setImage(String image) {
Image = image;
}
}
SingleSearchType1Model.java This is my second model file.
public class SingleSearchType1Model {
String Image;
public SingleSearchType1Model() {
}
public SingleSearchType1Model(String image) {
Image = image;
}
public String getImage() {
return Image;
}
public void setImage(String image) {
Image = image;
}
}
RecyclerView Adapters
Adapters are the ones used to set the value to the recyclerView. I have three Adapters as I'm trying to insert two views in one recyclerview. One is the MainAdapter which combines the other two Adapters. The MainAdapter is set to the the recyclerview of fragment_search.java (my main fragment)
SearchBannerAdapter.java This adapter is to generate the required layout file and populate the inflated layout file.
public class SearchBannerAdapter extends RecyclerView.Adapter<SearchBannerAdapter.TaskViewHolder>{
List<SingleSearchBannerModel> data;
public SearchBannerAdapter(List<SingleSearchBannerModel> data) {
this.data = data;
}
#NonNull
#Override
public TaskViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.search_single_banners,parent,false);
return new TaskViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull TaskViewHolder holder, int position) {
SingleSearchBannerModel singleSearchBannerModel = data.get(position);
Picasso.get().load(singleSearchBannerModel.getImage()).fit().into(holder.imageView);
}
#Override
public int getItemCount() {
return data.size();
}
public static class TaskViewHolder extends RecyclerView.ViewHolder{
View mView;
ImageView imageView;
public TaskViewHolder(View itemView) {
super(itemView);
mView = itemView;
imageView = mView.findViewById(R.id.search_banner_imgView);
}
}
}
search_single_banners.xml The xml file which is inflated in SearchBannerAdapter.java
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.CardView
android:layout_width="290dp"
android:layout_height="160dp"
android:id="#+id/longCard"
android:layout_marginTop="50dp"
android:layout_marginEnd="20dp"
app:cardCornerRadius="20sp"
app:cardElevation="#dimen/ten"
app:cardPreventCornerOverlap="false"
android:layout_centerHorizontal="true">
<ImageView
android:id="#+id/search_banner_imgView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/test1"/>
</android.support.v7.widget.CardView>
SearchType1Adapter.java This is the second adapter which inflates search_type_1.xml
public class SearchType1Adapter extends RecyclerView.Adapter<SearchType1Adapter.TaskViewHolder>{
List<SingleSearchType1Model> data;
public SearchType1Adapter(List<SingleSearchType1Model> data) {
this.data = data;
}
#NonNull
#Override
public TaskViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.search_type_1,parent,false);
return new TaskViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull TaskViewHolder holder, int position) {
SingleSearchType1Model singleSearchType1Model = data.get(position);
Picasso.get().load(singleSearchType1Model.getImage()).fit().into(holder.imageView);
}
#Override
public int getItemCount() {
return data.size();
}
public static class TaskViewHolder extends RecyclerView.ViewHolder{
View mView;
ImageView imageView;
public TaskViewHolder(View itemView) {
super(itemView);
mView = itemView;
imageView = mView.findViewById(R.id.search_single_type_1_imgView);
}
}
}
search_type_1.xml The file that is inflated in SearchType1Adapter.java
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.CardView
android:layout_width="290dp"
android:layout_height="160dp"
android:id="#+id/longCard"
android:layout_marginTop="50dp"
android:layout_marginEnd="20dp"
app:cardCornerRadius="20sp"
app:cardElevation="#dimen/ten"
app:cardPreventCornerOverlap="false"
android:layout_centerHorizontal="true">
<ImageView
android:id="#+id/search_single_type_1_imgView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/test1"/>
</android.support.v7.widget.CardView>
SearchMainAdapter.java This is the main adapter which is used in fragment_search to populate the main recyclerview.
public class SearchMainAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<Object> items;
private final int BANNER = 1;
private final int TYPE1 = 2;
public SearchMainAdapter(Context context, List<Object> items) {
this.context = context;
this.items = items;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view;
RecyclerView.ViewHolder holder;
switch (viewType){
case BANNER:
view = inflater.inflate(R.layout.search_banners,parent,false);
holder = new BannerViewHolder(view);
break;
case TYPE1:
view = inflater.inflate(R.layout.search_type_1,parent,false);
holder = new Type1ViewHolder(view);
break;
default:
view = inflater.inflate(R.layout.search_banners,parent,false);
holder = new Type1ViewHolder(view);
break;
}
return holder;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if(holder.getItemViewType() == BANNER)
BannerView((BannerViewHolder) holder);
else if (holder.getItemViewType() == TYPE1)
Type1View((Type1ViewHolder) holder);
}
private void BannerView(BannerViewHolder holder){
SearchBannerAdapter searchBannerAdapter = new SearchBannerAdapter(getBannerData());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false));
holder.recyclerView.setAdapter(searchBannerAdapter);
}
private void Type1View(Type1ViewHolder holder){
SearchType1Adapter searchType1Adapter = new SearchType1Adapter(getType1Data());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false));
holder.recyclerView.setAdapter(searchType1Adapter);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof SingleSearchBannerModel)
return BANNER;
if (items.get(position) instanceof SingleSearchType1Model)
return TYPE1;
return -1;
}
public static class BannerViewHolder extends RecyclerView.ViewHolder{
RecyclerView recyclerView;
public BannerViewHolder(View itemView) {
super(itemView);
recyclerView = itemView.findViewById(R.id.recyclerview_banners);
}
}
public static class Type1ViewHolder extends RecyclerView.ViewHolder{
RecyclerView recyclerView;
public Type1ViewHolder(View itemView) {
super(itemView);
recyclerView = itemView.findViewById(R.id.recyclerview_search_type_1);
}
}
}
search_banners.xml and search_type_1.xml have the same code
<android.support.constraint.ConstraintLayout
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/recyclerview_banners"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
The above code is not working. I want to know where i went wrong. My main objective is to make an app something like google play store or hotstar (In terms of UI). So I assume they are using single recyclerview and multiple view within it.
Thanks for help.
I know this answer is a bit late but it might still help someone in future. Here is how I achived the goal
public class HeteroActivity extends AppCompatActivity {
private ArrayList<Object> objects = new ArrayList<>();
private static final String TAG = HeteroActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hetero);
RecyclerView recyclerView = findViewById(R.id.recycler_View);
MainAdapter adapter = new MainAdapter(this, getObject());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
private ArrayList<Object> getObject() {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Data");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
objects.add(getVerticalData(dataSnapshot).get(0));
objects.add(getHorizontalData(dataSnapshot).get(0));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
return objects;
}
public static ArrayList<SingleVertical> getVerticalData(DataSnapshot dataSnapshot) {
ArrayList<SingleVertical> singleVerticals = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
singleVerticals.add(new SingleVertical(
snapshot.child("price").getValue(String.class),
snapshot.child("location").getValue(String.class),
snapshot.child("image").getValue(String.class)
));
Log.e(TAG,"Text loaded");
}
return singleVerticals;
}
public static ArrayList<SingleHorizontal> getHorizontalData(DataSnapshot dataSnapshot) {
ArrayList<SingleHorizontal> singleHorizontals = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
singleHorizontals.add(new SingleHorizontal(
snapshot.child("price").getValue(String.class),
snapshot.child("location").getValue(String.class),
snapshot.child("image").getValue(String.class)
));
Log.e(TAG,"Horizontal data loaded");
}
return singleHorizontals;
}
}
Then in your main Adapter
do this:
private void verticalView(final VerticalViewHolder holder) {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Data");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
VerticalAdapter adapter1 = new VerticalAdapter(getVerticalData(dataSnapshot), context);
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context));
holder.recyclerView.setAdapter(adapter1);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void horizontalView(final HorizontalViewHolder holder) {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Data");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
HorizontalAdapter adapter = new HorizontalAdapter(getHorizontalData(dataSnapshot),context);
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
I have a fragment that is suppose to display the results of my alert dialog in my RecyclerView. Every time I click the "ADD" in my dialog, it adds duplicated results to my RecyclerView. I've searched and searched but cannot seem to find what I am doing wrong. I've tried adding .clear(); but if I add that, nothing shows up in my RecyclerView at all. I've added in my adapter getItemId and getItemViewType to return position; but the items still get duplicated. I've added adapter.setData(model) followed by adapter.notifyDataSetChange(); and my RecyclerView still shows duplicated items. The app runs so I have no logcat to post. Thank you.
Model
public class SubjectsModel
{
//private long id;
private String mTitle;
private String mTeacher;
public String getmTitle()
{
return mTitle;
}
public void setmTitle(String title)
{
this.mTitle = title;
}
public String getmTeacher()
{
return mTeacher;
}
public void setmTeacher(String teacher)
{
this.mTeacher = teacher;
}
}
Fragment
public class SubjectsFrag extends DialogFragment implements
SubjectsEditor.OnAddSubjectListener
{
private static final String TAG = SubjectsFrag.class.getSimpleName();
#NonNull
Context context;
private EditText titleView, teacherView;
private String sTitle, sTeacher;
public EmptyRecyclerView recyclerView;
public RecyclerView.LayoutManager layoutManager;
public RecyclerSubAdapter recyclerSubAdapter;
public ArrayList<SubjectsModel> subMod = new ArrayList<>();
DbHelper helper;
#BindView(R.id.main_root)
ViewGroup root;
public SubjectsFrag() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_subjects, container, false);
FloatingActionButton fab = view.findViewById(R.id.fab_sub);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showDialog();
}
});
helper = new DbHelper(getActivity());
helper.getSubject();
titleView = view.findViewById(R.id.edit_subject);
teacherView = view.findViewById(R.id.edit_subject_teacher);
View emptyView = view.findViewById(R.id.empty_subject_view);
recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerSubAdapter = new RecyclerSubAdapter(getContext(), subMod);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(recyclerSubAdapter);
return view;
}
#Override
public void OnAddSubjectSubmit(String title, String teacher)
{
SubjectsModel model = new SubjectsModel();
model.setmTitle(title);
model.setmTeacher(teacher);
//subMod.clear();
subMod.add(model);
recyclerSubAdapter.setData(subMod);
recyclerSubAdapter.notifyDataSetChanged();
}
private void showDialog()
{
SubjectsEditor addSubjectDialog = new SubjectsEditor();
addSubjectDialog.setTargetFragment(this, 0);
addSubjectDialog.show(getFragmentManager(), null);
}
}
Adapter
public class RecyclerSubAdapter extends RecyclerView.Adapter<RecyclerSubAdapter.ViewHolder>
{
private static final String TAG = RecyclerSubAdapter.class.getSimpleName();
public List<SubjectsModel> subMod = new ArrayList<>();
private OnItemClicked onClick;
static ClickListener clickListener;
Context context;
DbHelper helper;
public RecyclerSubAdapter(Context context, ArrayList<SubjectsModel> subMod)
{
this.context = context;
this.subMod = subMod;
this.helper = new DbHelper(context);
}
#NonNull
#Override
public RecyclerSubAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.subjects_item_list, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(final RecyclerSubAdapter.ViewHolder holder, final int position)
{
SubjectsModel currentSubject = subMod.get(position);
holder.titleView.setText(currentSubject.getmTitle());
holder.teacher.setText(currentSubject.getmTeacher());
//helper.addClass(subMod.get(position));
}
public class ViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener
{
TextView titleView;
TextView teacher;
CardView cardView;
public ViewHolder(View itemView)
{
super(itemView);
titleView = itemView.findViewById(R.id.subject_subject);
teacher = itemView.findViewById(R.id.subject_teacher_text);
cardView = itemView.findViewById(R.id.card_view);
}
#Override
public void onClick(View view)
{
if (clickListener != null)
{
}
}
}
#Override
public int getItemCount()
{
if (subMod == null)
{
Log.d(TAG, "sub is null");
}
return subMod.size();
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public int getItemViewType(int position)
{
return position;
}
public interface OnItemClicked
{
void onItemClick(int position);
}
public void setOnClick(OnItemClicked onClick)
{
this.onClick = onClick;
}
public void setClickListener(ClickListener clicked)
{
RecyclerSubAdapter.clickListener = clicked;
}
public interface ClickListener
{
void itemClicked(SubjectsModel model, int position);
}
public void setData(ArrayList<SubjectsModel> data)
{
this.subMod = data;
//this.subMod.clear();
this.subMod.addAll(data);
notifyDataSetChanged();
}
}
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:id="#+id/main_root">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.ashleighwilson.schoolscheduler.adapter.EmptyRecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="60dp"/>
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="#+id/empty_subject_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone"
android:text="#string/no_subjects"/>
</RelativeLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab_sub"
style="#style/FAB" />
</RelativeLayout>
In OnAddSubjectSubmit() you call subMod.add(model);
and then you call recyclerSubAdapter.setData(subMod); which in turn calls this.subMod.addAll(data);.
Check it yourself. I believe it's there where you add the new item twice.
Suggestion: comment out recyclerSubAdapter.setData(subMod); from OnAddSubjectSubmit().
this.subMod = data;
this.subMod.addAll(data);
You initilize subMod by assigning data to it, and later you add data again:
this.subMod.addAll(data);