I have a problem that many people had but i don't understand how can i get out of it.
Please help me in my case and do not mark as duplicated.
I have a recyclerview linked with firebase.
My recyclerview has a custom adapter called MyAdapter:
public class MyAdapter extends RecyclerView.Adapter<MyHolder> implements Filterable {
Context c;
ArrayList<Studi> studi;
ArrayList<Studi> filterList;
CustomFilter filter;
public MyAdapter(Context c, ArrayList<Studi> studi) {
this.c = c;
this.studi = studi;
this.filterList = studi;
}
#Override
public MyHolder onCreateViewHolder (ViewGroup parent, int viewType){
View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.model, parent, false);
MyHolder holder = new MyHolder(v);
return holder;
}
#Override
public void onBindViewHolder (MyHolder holder, int position){
String name = studi.get(position).getName();
String desc = studi.get(position).getDescription();
String prof = studi.get(position).getProfessione();
String tel = studi.get(position).getTelefono();
String coord1 = studi.get(position).getCoordinata1();
String coord2 = studi.get(position).getCoordinata2();
String distanza = studi.get(position).getDistanza();
holder.nameTxt.setText(name);
holder.descTxt.setText(desc);
holder.profTxt.setText(prof);
holder.telTxt.setText(tel);
holder.pos1Txt.setText(coord1);
holder.pos2Txt.setText(coord2);
holder.distanza.setText(distanza);
}
#Override
public int getItemCount (){
return (studi == null) ? 0 : studi.size();
}
//FILTER THING......................
public Filter getFilter() {
if(filter == null)
{
filter=new CustomFilter(filterList,this);
}
return filter;
}}
All the items have got a textview inside where it is written the String Distanza. This string is a number for each recyclerview item.
I need to reorder all the recyclerview items from the lower to the higher (Value of the String Distanza).
This is my Studi class which i use for the arraylist:
public class Studi {
private String name;
private String description;
private String professione;
private String telefono;
private String coordinata1;
private String coordinata2;
private String distanza;
public void setDistanza(String distanza) {
this.distanza = distanza;
}
public String getDistanza() {
return distanza;
}
public String getCoordinata2() {
return coordinata2;
}
public void setCoordinata2(String coordinata2) {
this.coordinata2 = coordinata2;
}
public String getCoordinata1() {
return coordinata1;
}
public void setCoordinata1(String coordinata1) {
this.coordinata1 = coordinata1;
}
public String getProfessione() {
return professione;
}
public void setProfessione(String professione) {
this.professione = professione;
}
public String getTelefono() {
return telefono;
}
public void setTelefono(String telefono) {
this.telefono = telefono;
}
public Studi() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}}
So at the end, i need to reorder them at the top of the recyclerview from the ones that return a getDistanza() value lower than the others.
How can i do it? I have really no idea, and sorry but i am new at this.
You can sort your data before passing it to MyAdapter. You can use the sort method from the Collections class. You would have something like this:
Collections.sort(studi, new Comparator<Studi>() {
public int compare(Studi s1, Studi s2) {
return s1.getDistanza() - s2.getDistanza();
}
})
At the end, whenever you filter your data, it always will respect the getDistanza sorting.
You should not sort your data while you are inflating your recyclerView. Infact now that you are already fetching your data from firebase-database, you should use your query accordingly to get the result in sorted form.
If you want your list to be in increasing order of distance (distanza in your case), just use a query something like this
const query = itemsRef.orderByChild('distanza');
This will give you a sorted array which you dont need to sort anymore.
P.S. If you want your recyclerView to have changes in real-time, do not use your custom adapter, instead use the firebaseRecyclerviewAdapter.
Related
I have firestore database with root products and every products has collection 'comments' so i stored in it all users comments about this product , but when query on this comments sub-collection i get null values or zero snapshots from firestore
private void getCommentObject(){
query = FirebaseFirestore.getInstance()
.collection("products").document(docID).collection("comments");
FirestoreRecyclerOptions<CommentModel> options = new FirestoreRecyclerOptions.Builder<CommentModel>()
.setQuery(query, CommentModel.class)
.build();
adapter = new FirestoreRecyclerAdapter<CommentModel, commentHolder>(options) {
#NonNull
#Override
public commentHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.comment_item_layout, parent, false);
return new commentHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull commentHolder commentHolder, int position, #NonNull CommentModel commentModel) {
commentHolder.full_comment.setText(String.valueOf(commentModel.getComment()));
commentHolder.comment_date.setText(String.valueOf(commentModel.getCommentDate()));
commentHolder.comment_user.setText(String.valueOf(commentModel.getCommentUser()));
Glide.with(getApplicationContext())
.load(commentModel.getProfilePic())
.into(commentHolder.userProfileImg);
};
};
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
and here is my commentModel calss
#IgnoreExtraProperties
public class CommentModel implements Serializable {
public CommentModel() {
}
String comment , commentDate , profilePic , commentUser ;
public CommentModel(String comment) {
this.comment = comment;
}
public String getComment() {
return this.comment;
}
public void setComment(String Comment) {
this.comment = comment;
}
public String getCommentDate() {
return this.commentDate;
}
public void setCommentDate(String commentDate) {
commentDate = commentDate;
}
public String getProfilePic() {
return profilePic;
}
public void setProfilePic(String profilePic) {
this.profilePic = profilePic;
}
public String getCommentUser() {
return commentUser;
}
public void setCommentUser(String commentUser) {
commentUser = commentUser;
}
}
The problem in your code lies in the fact that the name of the fields in your CommentModel class are different than the name of the properties in your database. You have in your CommentModel class a field named comment but in your database I see it as Comment and this is not correct. The names must match. When you are using a getter named getComment(), Firebase is looking in the database for a field named comment and not Comment. See the lowercase c letter vs. capital letter C?
There are two ways in which you can solve this problem. The first one would be to change your model class by renaming the fields according to the Java Naming Conventions. So you model class should look like this:
public class CommentModel {
private String comment, commentDate, profilePic, commentUser;
public CommentModel() {}
public CommentModel(String comment, String commentDate, String profilePic, String commentUser) {
this.comment = comment;
this.commentDate = commentDate;
this.profilePic = profilePic;
this.commentUser = commentUser;
}
public String getComment() { return comment; }
public String getCommentDate() { return commentDate; }
public String getProfilePic() { return profilePic; }
public String getCommentUser() { return commentUser; }
}
See in this example, there are private fields and public getters. There is also a simpler solution, to set the value directly on public fields like this:
public class CommentModel {
public String comment, commentDate, profilePic, commentUser;
}
Now just remove the current data and add it again using the correct names. This solution will work only if you are in testing phase.
There is also the second approach, which is to use annotations. So if you prefer to use private fields and public getters, you should use the PropertyName annotation only in front of the getter. So your CommentModel class should look like this:
public class CommentModel {
private String comment, commentDate, profilePic, commentUser;
public CommentModel() {}
public CommentModel(String comment, String commentDate, String profilePic, String commentUser) {
this.comment = comment;
this.commentDate = commentDate;
this.profilePic = profilePic;
this.commentUser = commentUser;
}
#PropertyName("Comment")
public String getComment() { return comment; }
#PropertyName("CommentDate")
public String getCommentDate() { return commentDate; }
#PropertyName("ProfilePic")
public String getProfilePic() { return profilePic; }
#PropertyName("CommentUser")
public String getCommentUser() { return commentUser; }
}
Don't also forget to start listening for changes.
P.S. In your class, it should be:
this.commentDate = commentDate;
and not:
commentDate = commentDate;
I have firestore database with root products and every products has collection 'comments' so i stored in it all users comments about this product , but when query on this comments sub-collection i get null values or zero snapshots from firestore
private void getCommentObject(){
query = FirebaseFirestore.getInstance()
.collection("products").document(docID).collection("comments");
FirestoreRecyclerOptions<CommentModel> options = new FirestoreRecyclerOptions.Builder<CommentModel>()
.setQuery(query, CommentModel.class)
.build();
adapter = new FirestoreRecyclerAdapter<CommentModel, commentHolder>(options) {
#NonNull
#Override
public commentHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.comment_item_layout, parent, false);
return new commentHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull commentHolder commentHolder, int position, #NonNull CommentModel commentModel) {
commentHolder.full_comment.setText(String.valueOf(commentModel.getComment()));
commentHolder.comment_date.setText(String.valueOf(commentModel.getCommentDate()));
commentHolder.comment_user.setText(String.valueOf(commentModel.getCommentUser()));
Glide.with(getApplicationContext())
.load(commentModel.getProfilePic())
.into(commentHolder.userProfileImg);
};
};
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
and here is my commentModel calss
#IgnoreExtraProperties
public class CommentModel implements Serializable {
public CommentModel() {
}
String comment , commentDate , profilePic , commentUser ;
public CommentModel(String comment) {
this.comment = comment;
}
public String getComment() {
return this.comment;
}
public void setComment(String Comment) {
this.comment = comment;
}
public String getCommentDate() {
return this.commentDate;
}
public void setCommentDate(String commentDate) {
commentDate = commentDate;
}
public String getProfilePic() {
return profilePic;
}
public void setProfilePic(String profilePic) {
this.profilePic = profilePic;
}
public String getCommentUser() {
return commentUser;
}
public void setCommentUser(String commentUser) {
commentUser = commentUser;
}
}
The problem in your code lies in the fact that the name of the fields in your CommentModel class are different than the name of the properties in your database. You have in your CommentModel class a field named comment but in your database I see it as Comment and this is not correct. The names must match. When you are using a getter named getComment(), Firebase is looking in the database for a field named comment and not Comment. See the lowercase c letter vs. capital letter C?
There are two ways in which you can solve this problem. The first one would be to change your model class by renaming the fields according to the Java Naming Conventions. So you model class should look like this:
public class CommentModel {
private String comment, commentDate, profilePic, commentUser;
public CommentModel() {}
public CommentModel(String comment, String commentDate, String profilePic, String commentUser) {
this.comment = comment;
this.commentDate = commentDate;
this.profilePic = profilePic;
this.commentUser = commentUser;
}
public String getComment() { return comment; }
public String getCommentDate() { return commentDate; }
public String getProfilePic() { return profilePic; }
public String getCommentUser() { return commentUser; }
}
See in this example, there are private fields and public getters. There is also a simpler solution, to set the value directly on public fields like this:
public class CommentModel {
public String comment, commentDate, profilePic, commentUser;
}
Now just remove the current data and add it again using the correct names. This solution will work only if you are in testing phase.
There is also the second approach, which is to use annotations. So if you prefer to use private fields and public getters, you should use the PropertyName annotation only in front of the getter. So your CommentModel class should look like this:
public class CommentModel {
private String comment, commentDate, profilePic, commentUser;
public CommentModel() {}
public CommentModel(String comment, String commentDate, String profilePic, String commentUser) {
this.comment = comment;
this.commentDate = commentDate;
this.profilePic = profilePic;
this.commentUser = commentUser;
}
#PropertyName("Comment")
public String getComment() { return comment; }
#PropertyName("CommentDate")
public String getCommentDate() { return commentDate; }
#PropertyName("ProfilePic")
public String getProfilePic() { return profilePic; }
#PropertyName("CommentUser")
public String getCommentUser() { return commentUser; }
}
Don't also forget to start listening for changes.
P.S. In your class, it should be:
this.commentDate = commentDate;
and not:
commentDate = commentDate;
I have googled for a whole day but I just can't find an answer to my problem.
I'm using the MVC pattern.
Basically I have a list of songs (id, title, author, ect.) that I need to display in a JTable. The songs are stored in a MySQL database.The Connection to database works fine.
I'm currently storing all the reconds from my database in an 'ArrayList'
This is what I have so far:
The code to store the songs:
SongDAO songDAO = new SongDAO();
ArrayList<Song> songs = songDAO.findAll();
When printing out the songs, I get this output:
[oop.model.entities.Song#1055e4af, oop.model.entities.Song#3caeaf62, oop.model.entities.Song#e6ea0c6, oop.model.entities.Song#6a38e57f]
This is where I play the first song:
if (songs.isEmpty()) {
library = null;
} else {
library = songs.get(0);
Mainframe.setVisible(true);
firstController();
}
public static Library getLibrary() {
return library;
}
The library static factory method:
public static void firstController() {
new libraryController(view.libraryView);
}
I'm pretty sure the problem is here. I just can't figure it out for the life of me.
public class libraryController {
private libraryView view;
public libraryController(libraryView view) {
this.view = view;
for (Song song : baseController.getLibrary().getSongs()) {
view.addSong(song);
}
updateView();
}
public void updateView() {
view.setSongs(baseController.getLibrary().getSongs());
}
}
I've tried System.out.println(baseController.getLibrary().getSongs()), but all i get is [ ]. This leads me to believe the getSongs() method is the cause.
public void setSongs(ArrayList<Song> songs) {
for (Song song : songs) {
addSong(Song);
}
}
public void addSong(Song song) {
Object[] row = new Object[]{song.getId(), song.getTitle(), song.getArtist(), song.getAlbum(), song.getGenre(), song.getYear()};
model.addRow(row);
}
Here is my Library Class:
public class Library {
private ArrayList<Song> songs;
private int id;
private Song song;
public Library() {
id=0;
songs = new ArrayList<Song>(20);
}
public ArrayList<Song> getSongs() {
return songs;
}
public Libreria setSongs(ArrayList<Song> songs) {
this.songs = songs;
return this;
}
}
My song class:
public class Song extends Library {
private int id;
private String title;
private String artist;
private String album;
private String genre;
private int year;
private Library library;
public Song(){
id = 0;
}
public int getId() {return id; }
public void setId(int id) {this.id = id;}
public String getTitle() { return title;}
public void setTitle(String title) {this.title = title;}
public String getArtist() { return artist;}
public void setArtist(String artist) {this.artist = artist;}
public String getAlbum() {return album;}
public void setAlbum(String album) {this.album = album; }
public String getGenre() {return genre;}
public void setGenre(String genre) {this.genre = genre;}
public int getYear() {return year;}
public void setYear(int year) {this.year = year;}
public Library getLibrary() {return library;}
public Song setLibrary(Library library) {
this.library = library;
return this;
}
}
If anyone could help me, that would be greatly appreciated.
Basically i have to display in JTable my songs ('id','title,'author','..')
Swing components are already designed using a modified version of MVC.
If you want to display data in a JTable you just need to load the data into a TableModel.
So you may want to create a custom TableModel so hold your Song objects.
Check out Table Row Model.
It shows you step by step how to create a custom model for the Song object. Or if you want you can use the generic TableRowModel to make the coding easier.
Once you create the SongTableModel the code to use it would be something like:
SongTableModel model = new SongTableModel( songs );
JTable table = new JTable( model );
I have two spinners, one where the user selects the food type and a second that is meant to display the food (e.g. Breakfast and Porridge). However my second spinner isn't displaying my foods. Why would this appear? Below is my MainActivity class and my Food class code.
private void chooseBreakfast() {
planspinner1 = (Spinner) findViewById(R.id.planspinner);
List<Food> planlist = new ArrayList<Food>();
planlist.add(new Food("Porridge-35g/140cal",4));
planlist.add(new Food("Coffee-10g/10cal",1));
planlist.add(new Food("Toast-30g/90cal",3));
for(int i =0;i<planlist.size();i++){
System.out.println(planlist.get(i).getName()+ "has" + planlist.get(i).getCalories()+ "calories.");
}
ArrayAdapter<Food> planAdapter1 = new ArrayAdapter<Food>(this,android.R.layout.simple_spinner_item, planlist);
planAdapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
planspinner1.setAdapter(planAdapter1);
}
public class Food {
private String mstrName;
private int mintCalories;
public Food(String pstrName, int pintCalories) {
mstrName = pstrName;
mintCalories = pintCalories;
}
public String getName() {
return mstrName;
}
public int getCalories() {
return mintCalories;
}
}
Why would my second spinner appear like this?
Override toString() method of your Food class and it might work.
public class Food {
private String mstrName;
private int mintCalories;
public Food(String pstrName, int pintCalories) {
mstrName = pstrName;
mintCalories = pintCalories;
}
public String getName() {
return mstrName;
}
public int getCalories() {
return mintCalories;
}
public String toString() {
return getName();
}
}
I have custom class that implements Parcelable and I use it as custom arraylist.
When I use putParcelableArrayListExtra and 400 rows it works fine, but 1000 rows it does not. I have black screen and app locks up. What is wrong?
EDIT:
I sent it here and I don't use it in another Activity.
Intent intent = new Intent().setClass(getApplicationContext(), ArtActivity.class);
intent.putParcelableArrayListExtra ("mylist", list);
startActivityForResult(intent, SECONDARY_ACTIVITY_REQUEST_CODE);
My array:
ArrayList<Piece> list = new ArrayList<Piece>();
It is my Class:
public class Piece implements Parcelable {
private String id;
private String name;
private int type;
private String text;
private String mp3;
public Piece (String id,String name,int type)
{
this.id=id;
this.name=name;
this.type=type;
}
public Piece(Piece ele)
{
this.id=ele.id;
this.name=ele.name;
this.type=ele.type;
this.text=ele.text;
}
public Piece (Parcel in)
{
id = in.readString ();
name = in.readString ();
type = in.readInt();
text= in.readString();
mp3=in.readString();
}
public static final Parcelable.Creator<Piece> CREATOR
= new Parcelable.Creator<Piece>()
{
public Piece createFromParcel(Parcel in)
{
return new Piece(in);
}
public Piece[] newArray (int size)
{
return new Piece[size];
}
};
public void makeText(String text)
{
this.text=text;
}
public void makeMp3(String mp3)
{
this.mp3= mp3;
}
public String getMp3()
{
return this.mp3;
}
public String getId()
{
return id;
}
public String getName()
{
return name;
}
public int getType()
{
return type;
}
public String getText()
{
return text;
}
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString (id);
dest.writeString (name);
dest.writeInt(type);
dest.writeString (text);
dest.writeString (mp3);
}
}
I do not believe you should be using parcelable in this case. I would either access the data statically (if you only intend to have one persistent instance of the data), or use a caching system to hold onto the data.
This is an example of a publicly available static variable:
public static List<Piece> list;
It is accessible from everywhere in your app that has visibility of the class.
However, doing this is very messy and is considered a bad practice. Alternatively, you can create an object to manage the data for you as a static class or singleton:
public class MyListManager {
private static List<Piece> mList;
public static List<Piece> getMyList() {
return mList;
}
public static void setList(List<Piece> list) {
mList = list;
}
}
Alternatively, you can implement some kind of a caching system to manage your data.