I trying to show firebase data by using recyclerview.
retrieving data is well, I can check it in logcat.
Sometimes recyclerview show data, but Usually show nothing.
When recycleview show data, it is reflectled firebase data well.
Who can tell me What the problem?? Is there mistake in my xml code?
Java code
artistData.child(starList[i]).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot starDataSnap) {
int fanNums = (int) starDataSnap.child("fanNums").getValue(Integer.class);
int placeNums = (int) starDataSnap.child("placeNums").getValue(Integer.class);
Log.d("####", finalStarName + fanNums + placeNums);
drawerStarImage = getResources().getIdentifier(finalStarImgName, "drawable", getActivity().getPackageName());
ItemStarData itemStarData = new ItemStarData();
itemStarData.setStarImage(drawerStarImage);
itemStarData.setStarName(finalStarName);
itemStarData.setFanNums(fanNums);
itemStarData.setPlaceNums(placeNums);
drawerStarList.add(itemStarData);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Adapter class code
public class AdapterStarlist extends RecyclerView.Adapter<AdapterStarlist.ViewHolder>{
ArrayList<ItemStarData> array;
Context context;
public AdapterStarlist(ArrayList<ItemStarData> array, Context context) {
this.array = array;
this.context =context;
}
#NonNull
#Override
public AdapterStarlist.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_home_starlist,parent,false);
return new AdapterStarlist.ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull AdapterStarlist.ViewHolder holder, int position) {
Log.d("####", array.get(position).getStarName());
holder.Imgstarlist.setImageResource(array.get(position).getStarImage());
holder.followStarName.setText(String.valueOf(array.get(position).getStarName()));
holder.starlistfanNum.setText(String.valueOf(array.get(position).getFanNums()));
holder.starlistPlaceNum.setText(String.valueOf(array.get(position).getPlaceNums()));
}
#Override
public int getItemCount() {
return array.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView Imgstarlist;
TextView followStarName;
TextView starlistfanNum;
TextView starlistPlaceNum;
public ViewHolder(#NonNull View itemView) {
super(itemView);
Imgstarlist =itemView.findViewById(R.id.Imgstarlist);
followStarName =itemView.findViewById(R.id.followStarName);
starlistfanNum =itemView.findViewById(R.id.starlistfanNum);
starlistPlaceNum =itemView.findViewById(R.id.starlistPlaceNum);
Imgstarlist.setBackground(new ShapeDrawable(new OvalShape()));
Imgstarlist.setClipToOutline(true);
}
}
}
Part of xml code
<ScrollView
android:layout_width="match_parent"
android:layout_height="480dp"
android:layout_marginTop="24dp"
android:fillViewport="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/DrawerStarlist"
>
<RelativeLayout
android:id="#+id/rlDrawerStarlist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/DrawerStarlist">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvDrawerStarlist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
</RelativeLayout>
</ScrollView>
It looks like you're adding the data to the drawerStarList list, but not telling the adapter that you've done so. Until you tell the adapter of the change (by calling notifyDataSetChanged() on it), it won't repaint the UI for the list.
So typically this would look something like:
artistData.child(starList[i]).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot starDataSnap) {
...
drawerStarList.add(itemStarData);
adapter.notifyDataSetChanged(); // tell the adapter to repaint its views
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // never ignore errors
}
});
With adapter being a reference to the adapter that you use to manage drawerStarList.
Related
I want to show a Progressbar when my data is being retrived from firebasedatabase into recyclerview, and hide it when its done. I searched online but no soln. works
here is my mainActivity
public class MemesSchool extends AppCompatActivity {
RecyclerView recyclerView;
MemeAdapter memeAdapter;
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
progressBar = (ProgressBar) findViewById(R.id.pbmeme);
setContentView(R.layout.activity_memes_school);
getWindow().setStatusBarColor(getResources().getColor(R.color.buttonclr));
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.buttonclr)));
getSupportActionBar().setTitle("School Memes");
recyclerView = findViewById(R.id.rvm);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
FirebaseRecyclerOptions < mememodel > options =
new FirebaseRecyclerOptions.Builder < mememodel > ()
.setQuery(FirebaseDatabase.getInstance().getReference().child("Memedata"), mememodel.class)
.build();
memeAdapter = new MemeAdapter(options);
recyclerView.setAdapter(memeAdapter);
}
#Override
protected void onStart() {
super.onStart();
memeAdapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
memeAdapter.stopListening();
}
}
here is my MainActivity.XML
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".MemesSchool">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="#+id/rvm"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foregroundGravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="#+id/pbmeme"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
my Adapterclass
public class MemeAdapter extends FirebaseRecyclerAdapter < mememodel, MemeAdapter.myViewHolder > {
public MemeAdapter(#NonNull FirebaseRecyclerOptions < mememodel > options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull myViewHolder holder, int position, #NonNull mememodel model) {
holder.username.setText(model.getNameuser());
holder.subuser.setText(model.getSubname());
holder.title.setText(model.getTitle());
Glide.with(holder.imgmeme.getContext()).load(model.getImagesurl())
.placeholder(R.drawable.logoinhanced)
.error(R.drawable.logoinhanced).into(holder.imgmeme);
}
#NonNull
#Override
public myViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.memes_item, parent, false);
return new myViewHolder(view);
}
#Override
public void onDataChanged() {
}
#Override
public void onError(#NonNull DatabaseError error) {
super.onError(error);
}
class myViewHolder extends RecyclerView.ViewHolder {
ImageView imgmeme;
TextView username, subuser, title;
public myViewHolder(#NonNull View itemView) {
super(itemView);
imgmeme = itemView.findViewById(R.id.meme);
username = itemView.findViewById(R.id.nameuser);
subuser = itemView.findViewById(R.id.subname);
title = itemView.findViewById(R.id.titlememe);
}
}
}
There Is an Mothod called ONDATACHANGE() when should be in adapter class and i dont know how to control my adapter class from there ;
what should happen :- a Progressbar should be visible when i open the Activity and it should hide when the data is loaded in the RecyclerView !
One way to hide the progress bar when the data is loaded is to pass it to your adapter in its constructor, and then hide it in onDataChanged:
public class MemeAdapter extends FirebaseRecyclerAdapter < mememodel, MemeAdapter.myViewHolder > {
View progressBar;
public MemeAdapter(#NonNull FirebaseRecyclerOptions <mememodel> options, View progressBar) {
super(options);
this.progressBar = progressBar;
}
...
#Override
public void onDataChanged() {
progressBar.setVisibility(View.GONE)
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am trying to fetch data from firebase and put it into a recycler view through adapter. But, no data is being displayed.
My code in Main Activity:
DatabaseReference databaseReference;
RecyclerView recyclerView;
ArrayList<Menu> menuList;
EditMenuAdapter editMenuAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_menu);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
menuList = new ArrayList<Menu>();
databaseReference = FirebaseDatabase.getInstance().getReference().child("menu");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Menu menu = dataSnapshot1.getValue(Menu.class);
menuList.add(menu);
}
editMenuAdapter = new EditMenuAdapter(EditMenuActivity.this, menuList);
recyclerView.setAdapter(editMenuAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(EditMenuActivity.this, "Something went wrong", Toast.LENGTH_LONG).show();
}
});
My adapter class:
public class EditMenuAdapter extends RecyclerView.Adapter<EditMenuAdapter.MyViewHolder> {
Context context;
ArrayList<Menu> menuArrayList;
public EditMenuAdapter(Context c, ArrayList<Menu> menus) {
context = c;
menuArrayList = menus;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.menu_list_layout, parent, false));
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.dishNameTextView.setText(menuArrayList.get(position).getDishName());
holder.dishPriceTextView.setText(menuArrayList.get(position).getDishPrice());
}
#Override
public int getItemCount() {
return menuArrayList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView dishNameTextView;
TextView dishPriceTextView;
Switch dishActiveSwitch;
public MyViewHolder(View view) {
super(view);
dishNameTextView = (TextView) view.findViewById(R.id.dishNameTextView);
dishPriceTextView = (TextView) view.findViewById(R.id.dishPriceTextView);
dishActiveSwitch = (Switch) view.findViewById(R.id.dishActiveSwitch);
}
}
}
The layout resource file is:
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".EditMenuActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="397dp"
android:layout_height="599dp"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/doneButton"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"
android:text="Done"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/recyclerView" />
The log shows: E/RecyclerView: No adapter attached; skipping layout. No data is displayed.
Only the switch is being displayed on the screen. Please help!
Create instance of adapter in onCreate and attach it to RV:
protected void onCreate(Bundle savedInstanceState) {
...
editMenuAdapter = new EditMenuAdapter(this, new ArrayList<>());
recyclerView.setAdapter(adapter);
...
}
In the response of Firebase onDataChange:
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
...
editMenuAdapter.setItems(menuList);
runOnUiThread(() -> editMenuAdapter.notifyDataSetChanged());
}
I am creating Android app, using room database.
I have two tables DogsTable:
#PrimaryKey(autoGenerate = true)
int dog_id;
String dogName;
and CatsTable (both tables have constructor and getter methods ):
#PrimaryKey(autoGenerate = true)
int cat_id;
String catName;
1- How to display in one RecyclerView two different object type
ArrayList<DogsTable> dog_list;
ArrayList<CatsTable> cat_list;
I am getting the values of dog_list and cat_list from ViewModel Query as show in MainActivity.class.
2- How to fix getItemCount() method? I don't know how to return two different object cat_list.size(); and dog_list.size();
3- Also in onBindViewHolder() method I don`t know how to get cat_list values to display them in UI?
4- Another problem is in swapToDelete() Method in MainActivity.class, I can get the dog id to delete it, but I can not get the cat id to delete it, how can I get the cat id ?
5- How can I display (dog1,dog2 , dog3) as show in first image? (i inserted the value manually in the first image just to show how i want to display them )
Existing Output as below:
My code
MainActivity.java
public class MainActivity extends AppCompatActivity implements MainActivityAdapter.ItemClickListener {
MyViewModel viewModel;
MainActivityAdapter adapter;
RecyclerView recyclerView;
LinearLayoutManager layoutManager;
Button btn_addDog, btn_addCat;
EditText et_addDogName, et_addCatName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
actionButton();
buildRecyclerView();
setUpViewModel_dogs();
swapToDelete_dog();
}
private void initViews() {
et_addDogName = findViewById(R.id.addDogNameET_xml);
et_addCatName = findViewById(R.id.addCatNameET_xml);
}
public void actionButton() {
btn_addDog = findViewById(R.id.AddDog_btn_xml);
btn_addCat = findViewById(R.id.AddCat_btn_xml);
btn_addDog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
insertDog();
}
});
btn_addCat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
insertCat();
}
});
}
private void buildRecyclerView() {
recyclerView = findViewById(R.id.recyclerView_id);
adapter = new MainActivityAdapter(this, this);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
// Query
public void setUpViewModel_dogs() {
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
viewModel.getAllDogs().observe(this, new Observer<List<DogsTable>>() {
#Override
public void onChanged(#Nullable List<DogsTable> dogsTables) {
adapter.setDog_list((ArrayList<DogsTable>) dogsTables);
}
});
}
public void setUpViewModel_cats(){
viewModel.getAllCats().observe(this, new Observer<List<CatsTable>>() {
#Override
public void onChanged(#Nullable List<CatsTable> catsTables) {
adapter.setCat_list((ArrayList<CatsTable>) catsTables);
}
});
}
// Add
public void insertDog() {
String dogName = String.valueOf(et_addDogName.getText()).trim();
DogsTable obj_dog = new DogsTable(dogName);
viewModel.insertDog(obj_dog);
Toast.makeText(this, "Dog Added", Toast.LENGTH_SHORT).show();
}
public void insertCat() {
String catName = String.valueOf(et_addCatName.getText());
CatsTable obj_cat = new CatsTable(catName);
viewModel.insertCat(obj_cat);
Toast.makeText(this, "cat Added", Toast.LENGTH_SHORT).show();
}
// Delete
public void swapToDelete_dog() {
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
List<DogsTable> dog_pos = adapter.getDog_list();
viewModel.deleteDog(dog_pos.get(viewHolder.getAdapterPosition()));
}
}
).attachToRecyclerView(recyclerView);
}
public void swapToDelete_cat() {
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int item_id = item.getItemId();
if (item_id == R.id.menu_add) {
Intent in = new Intent(this, Add.class);
startActivity(in);
}
return super.onOptionsItemSelected(item);
}
#Override
public void onItemClickListener(int pet_id) {
}
}
activity_main.xml
<?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"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/addDogNameET_xml"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="add Dog name" />
<Button
android:id="#+id/AddDog_btn_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/addCatNameET_xml"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="add Cat name" />
<Button
android:id="#+id/AddCat_btn_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints" />
</LinearLayout>
MainActivityAdapter.java
public class MainActivityAdapter extends RecyclerView.Adapter<MainActivityAdapter.MyViewHolder> {
Context mContext;
ArrayList<DogsTable> dog_list;
ArrayList<CatsTable> cat_list;
ItemClickListener mItemClickListener;
public MainActivityAdapter(Context context , ItemClickListener itemClickListener) {
this.mContext = context;
this.mItemClickListener = itemClickListener;
}
public interface ItemClickListener {
void onItemClickListener(int pet_id);
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.activity_main_adapter, viewGroup, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
DogsTable dog_pos = dog_list.get(position);
// CatsTable catsTable = cat_list.get(position);
holder.dogName.setText(String.valueOf(dog_pos.getDogName()));
// holder.catName.setText(String.valueOf(catsTable.getCatName()));
}
#Override
public int getItemCount() {
if (dog_list == null ) {
return 0;
} else {
return dog_list.size();
}
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener , ItemClickListener {
TextView dogName;
TextView catName;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
dogName = itemView.findViewById(R.id.dogName_xml);
catName = itemView.findViewById(R.id.catName_xml);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int pet_id = dog_list.get(getAdapterPosition()).getDogs_id();
mItemClickListener.onItemClickListener(pet_id);
}
#Override
public void onItemClickListener(int pet_id) {
int pos = dog_list.get(getAdapterPosition()).getDogs_id();
mItemClickListener.onItemClickListener(pet_id);
}
}
public void setDog_list(ArrayList<DogsTable> dog_list) {
this.dog_list = dog_list;
notifyDataSetChanged();
}
public ArrayList<DogsTable> getDog_list() {
return dog_list;
}
public void setCat_list(ArrayList<CatsTable> cat_list) {
this.cat_list = cat_list;
}
}
activity_main_adapter.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:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dogs: " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/dogName_xml"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<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="Cats: " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/catName_xml"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
To support different view types, RecyclerView.Adapter provides a useful method int getItemViewType(int position):
Return the view type of the item at position for the purposes of view recycling.
The default implementation of this method returns 0, making the assumption of a single view type for the adapter. Unlike ListView adapters, types need not be contiguous. Consider using id resources to uniquely identify item view types.
Then, in onCreateViewHolder you can see that a second parameter is int viewType which comes from the method int getItemViewType(int position). Based on that, you can instantiate a ViewHolder you need, e.g. DogViewHolder or CatViewHolder.
But what about storing multiple view models in a single adapter and defining which ViewHolder type should be actually instantiated? Here are two most popular approaches:
Declaring multiple containers for multiple types and defining a custom logic for getItemViewType method, e.g. all odd numbers will go in the dogs' list and even numbers will go in the cats' list (or any other method, but beware that you will have to cope with different lists' sizes and all the view types you need). Also, getItemsCount should be overriden appropriately (return list1.size() + list2.size + ... + listN.size();)
Put all the view models in a single list and perform some kind of attributes checks: either it will be some property or the type itself (not recommended for scalability reasons). Then your code will look like this:
public int getItemViewType(int position) {
CommonParentForUpcasting item = items.get(position);
if (item instanceOf Dog) { // or something like item.type == Animal.CAT
return R.id.holder_dog;
} else {
return R.id.holder_cat;
}
}
If you want to come up with a second solution, this solution should suit you well.
Also, make sure to check this StackOverflow answer.
I making a list of usernames and call buttons, each username has a call button next to it, when I click the call button the code inside the call button does not get executed in all clicks, I tried to make the whole item clickable so that if the user clicks on the button, the username or any part in the layout_item the code gets executed but no change happened.
Here is how I am implementing the adapter:
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.freind_list_item, parent,false);
return new MyViewHolder(mView);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
Friend friend = friends.get(position);
holder.btnInitCallHandler(friend.getUsername(), friend.get_id());
holder.setUsername(friend.getUsername());
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView txtUsername;
Button btnInitCallWithFriend;
RelativeLayout rlInsteadOfButtonHandler;
MyViewHolder(View itemView) {
super(itemView);
txtUsername = itemView.findViewById(R.id.txt_friend_item);
btnInitCallWithFriend = itemView.findViewById(R.id.btnInitCallWithFriendNormal);
friendState = itemView.findViewById(R.id.onlineState);
signedAsGlasses = itemView.findViewById(R.id.signedInAsGlasses);
signedAsLaptop = itemView.findViewById(R.id.signedInAsLaptop);
rlInsteadOfButtonHandler = itemView.findViewById(R.id.rlInsteadButtonHandler);
}
void setUsername(String username) {
txtUsername.setText(username);
}
void btnInitCallHandler(String username, String userId) {
btnInitCallWithFriend.setOnClickListener((view) -> {
Timber.tag("KingArmstringNormalUserCall").d("normal user call button clicked from the adapter");
viewAccessor.initCall(username, userId);
});
rlInsteadOfButtonHandler.setOnClickListener((v) -> {
viewAccessor.initCall(username, userId);
});
}
}
the viewAccessor is just an interface implemented by the activity, and have only one method (initCall)
the initCall(username, userId) in the Activity has only a toast and a log
EDIT:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:background="#android:color/black"
android:padding="10dp">
<TextView
android:id="#+id/txt_friend_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/txt_friend_name_placeholder"
android:textSize="30sp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#color/colorAccent"/>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<RelativeLayout
android:id="#+id/rlInsteadButtonHandler"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<!--<at.markushi.ui.CircleButton-->
<!--android:id="#+id/btnInitCallWithFriend"-->
<!--android:layout_width="70dp"-->
<!--android:layout_height="40dp"-->
<!--android:src="#drawable/ic_video_call"-->
<!--android:layout_marginStart="10dp"-->
<!--android:layout_gravity="center"-->
<!--android:focusable="false"-->
<!--android:focusableInTouchMode="false"-->
<!--app:cb_color="#fff"-->
<!--android:layout_alignParentEnd="true"/>-->
<Button
android:id="#+id/btnInitCallWithFriendNormal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:focusable="true"
android:text="call" />
</RelativeLayout>
use below code on constructor of MyViewHolder class. This code makes an item clickable.
itemView.setClickable(true);
Also set onClickLiester on MyViewHolder class. Then use getAdapterPostion() method to determine which item clicked.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dataList.get(getAdapterPosition()); //this code will return the clicked item object.
});
First remove btnInitCallHandler() function from your ViewHolder, then set the clickListener directly in your viewHolder, you can get the current item from your list by calling getAdapterPosition() for exemple:
btnInitCallWithFriend.setOnClickListener((view) -> {
Timber.tag("KingArmstringNormalUserCall").d("normal user call button clicked from the adapter");
viewAccessor.initCall(friends.get(getAdapterPosition).getUsername(), friends.get(getAdapterPosition).get_id());
});
so this your new adapter class:
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.freind_list_item, parent,false);
return new MyViewHolder(mView);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
//do your stuff
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView txtUsername;
Button btnInitCallWithFriend;
RelativeLayout rlInsteadOfButtonHandler;
MyViewHolder(View itemView) {
super(itemView);
txtUsername = itemView.findViewById(R.id.txt_friend_item);
btnInitCallWithFriend = itemView.findViewById(R.id.btnInitCallWithFriendNormal);
friendState = itemView.findViewById(R.id.onlineState);
signedAsGlasses = itemView.findViewById(R.id.signedInAsGlasses);
signedAsLaptop = itemView.findViewById(R.id.signedInAsLaptop);
rlInsteadOfButtonHandler = itemView.findViewById(R.id.rlInsteadButtonHandler);
btnInitCallWithFriend.setOnClickListener((view) -> {
Timber.tag("KingArmstringNormalUserCall").d("normal user call button clicked from the adapter");
viewAccessor.initCall(friends.get(getAdapterPosition).getUsername(), friends.get(getAdapterPosition).get_id());
});
rlInsteadOfButtonHandler.setOnClickListener((v) -> {
viewAccessor.initCall(friends.get(getAdapterPosition).getUsername(), friends.get(getAdapterPosition).get_id());
});
}
void setUsername(String username) {
txtUsername.setText(username);
}
}
Following is a simple yet powerful implementation of RecylcerView. Try to read out the basics of recycler view and why viewholder is used. Hope this helps you out.
public class TestActivity extends Activity implements TestAdapter.ItemClickListener {
TestAdapter adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
ArrayList<String> testNames = new ArrayList<>();
testNames.add("Horse");
testNames.add("Cow");
testNames.add("Camel");
testNames.add("Sheep");
testNames.add("Goat");
RecyclerView recyclerView = findViewById(R.id.testList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new TestAdapter(this, testNames);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
}
#Override
public void onItemClick(View view, int position) {
Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
}}
Following is adapter class implementation
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder> {
private ItemClickListener mClickListener;
private List<String> mData;
private Activity mActivity;
public TestAdapter(TestActivity testActivity, ArrayList<String> testNames) {
this.mData = testNames;
this.mActivity = testActivity;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.test_row, parent, false);
return new MyViewHolder(mView);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
String animal = mData.get(position);
holder.txtUsername.setText(animal);
}
#Override
public int getItemCount() {
return mData.size();
}
public String getItem(int position) {
return mData.get(position);
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView txtUsername;
Button btnInitCallWithFriend;
MyViewHolder(View itemView) {
super(itemView);
txtUsername = itemView.findViewById(R.id.txt_friend_item);
btnInitCallWithFriend = itemView.findViewById(R.id.btnInitCallWithFriendNormal);
//friendState = itemView.findViewById(R.id.onlineState);
//signedAsGlasses = itemView.findViewById(R.id.signedInAsGlasses);
//signedAsLaptop = itemView.findViewById(R.id.signedInAsLaptop);
btnInitCallWithFriend.setOnClickListener((View view) -> {
Toast.makeText(mActivity, "You clicked call " + getAdapterPosition() + " position", Toast.LENGTH_SHORT).show();
});
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mClickListener != null) {
mClickListener.onItemClick(itemView, getAdapterPosition());
}
}
});
}
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}}
I have finally figured out whats happening, I have been handling lots of things in the foreground, I have transferred lots of them to other threads, now it worked, u might don't believe me, but many really experienced people said to me, that they encountered a very similar situations.
Left is Mary and right is Bill , the speaker's textView will show on the right side , the situation is that Mary says 1 and 2 , it looks fine , just like the photo:
next step : the right side device is Bill who says a and b , it looks fine that is just what i want.
when they type words more and more , my issue is happen like this:
But when i leave the ChatGroup1 and enter it again , it looks fine
So my issue is that it has something wrong with realtime on display recyclerView
How can i fix this issue , i try to add listData.clear(); , it's not working
Any help would be appreciated , thanks in advance .
It's my chat channel layout:
<?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/recyclerChat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/button2">
</android.support.v7.widget.RecyclerView>
<Button
android:id="#+id/button2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="#drawable/ic_send" />
<EditText
android:gravity="center"
android:hint="Type your message..."
android:background="#drawable/edit_corner"
android:id="#+id/editText2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="#+id/button2"
android:layout_toStartOf="#+id/button2" />
</RelativeLayout>
it's my chat class for Firebase and recyclerView:
//global variable
private RecyclerView recyclerChat;
private ArrayList<ChatItem> listData = new ArrayList<>();
private RecyclerChatItemAdapter adapter;
private DatabaseReference root;
About FirebaseDatabase:
root = FirebaseDatabase.getInstance().getReference().child(room_name);
//send message to FirebaseDatabase
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Map<String, Object> map = new HashMap<>();
temp_key = root.push().getKey();
root.updateChildren(map);
DatabaseReference message_root = root.child(temp_key);
Map<String, Object> map2 = new HashMap<>();
map2.put("name", user_name);
map2.put("msg", editText2.getText().toString());
message_root.updateChildren(map2);
manager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken() , InputMethodManager.HIDE_NOT_ALWAYS);//just hide the keyboard when send message
editText2.setText("");
}
});
I think that may be my issue is just right here , about my recyclerView:
root.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ChatItem chatItem = dataSnapshot.getValue(ChatItem.class);//put the data to my javabean from Firebase
Log.d("Contacts: ", chatItem.toString());
listData.add(chatItem);
recyclerChat.scrollToPosition(adapter.getItemCount() - 1);//just let the latest data below
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
//append_right_chat_conversation(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
LinearLayoutManager manager = new LinearLayoutManager(this);
// GridLayoutManager gridLayoutManager=new GridLayoutManager(this,2);
manager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerChat.setLayoutManager(manager);
adapter = new RecyclerChatItemAdapter(this, listData);
recyclerChat.setAdapter(adapter);
adapter.notifyDataSetChanged();//when i leave the chat group and enter again , it looks fine because this.
It's my recyclerView adapter:
public class RecyclerChatItemAdapter extends RecyclerView.Adapter<RecyclerChatItemAdapter.MyViewHolder>{
private Context context;
private List<ChatItem> mDatas;
public RecyclerChatItemAdapter(Context context, List<ChatItem> mDatas) {
this.context = context;
this.mDatas = mDatas;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=View.inflate(parent.getContext(),R.layout.for_chat_item_layout,null);
MyViewHolder myViewHolder=new MyViewHolder(view);
return myViewHolder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
String myName=mDatas.get(position).getName();
Contacts contacts=Contacts.getContacts();
String createName=contacts.getName();
if (myName.equals(createName)){
holder.textRight.setText(mDatas.get(position).getMsg()+"("+mDatas.get(position).getName()+")");
holder.textRight.setTextColor(Color.BLUE);
holder.textRight.setBackground(context.getResources().getDrawable(R.drawable.chat_green));
}else {
holder.textLeft.setText(mDatas.get(position).getMsg()+"("+mDatas.get(position).getName()+")");
holder.textLeft.setTextColor(Color.RED);
holder.textLeft.setBackground(context.getResources().getDrawable(R.drawable.chat_blue));
}
}
#Override
public int getItemCount() {
return mDatas.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder{
private TextView textLeft,textRight;
public MyViewHolder(View itemView) {
super(itemView);
textLeft=(TextView)itemView.findViewById(R.id.textLeft);
textRight=(TextView)itemView.findViewById(R.id.textRight);
}
}
}
You don't have shown Adapter layout and adapter code... It can be visibility problem of view.
You may be set visibility for view.. So for that please ensure that you have written something like this..
if (myName.equals(createName)){
holder.textRight.setVisibility(VISIBLE);
holder.textLeft.setVisibility(GONE);
holder.textRight.setText(mDatas.get(position).getMsg()+"("+mDatas.get(position).getName()+")");
holder.textRight.setTextColor(Color.BLUE);
holder.textRight.setBackground(context.getResources().getDrawable(R.drawable.chat_green));
}else {
holder.textRight.setVisibility(GONE);
holder.textLeft.setVisibility(VISIBLE);
holder.textLeft.setText(mDatas.get(position).getMsg()+"("+mDatas.get(position).getName()+")");
holder.textLeft.setTextColor(Color.RED);
holder.textLeft.setBackground(context.getResources().getDrawable(R.drawable.chat_blue));
}