I have two RealmObjects, something like,
public class Dog extends RealmObject {
#Required
private String name;
private int age;
}
public class Person extends RealmObject {
#Required
private String name;
private Dog dog; // A person has only one dog (a relationship)
}
In one of the activities, I want to let the user select the dog for the given person.
I thought I will use a spinner.
I also got a sample code from Realm-Examples, that did similar stuff for the ListView.
public class DogListAdapter extends RealmBaseAdapter<Dog> implements SpinnerAdapter
So far everything works fine. The spinner list automatically updates to reflect changes in the realm.
But, when I have to first display the GUI, I want to set the selected item to the current Person.dog.name.
What is the best way to do this?
I am doing something like this in onResume():
dogNameSpinner.setSelection(RealmUtils.resultIndexOf(dogsResult, person.getDog()));
where, the RealmUtils.resultIndexOf is a small utility function:
public static int resultIndexOf(RealmResults results, RealmObject obj) {
for(int i=0; i < results.size(); i++ ) {
if(results.get(i) == obj) {
return i;
}
}
return 0;
}
This does not work. I suspect may be because the realm.changeListeners get called and the spinner resets to the first item whenever items are updated.. ??
I suppose there could be a better way to do this as it should be a common model-view use case.
Related
I'm having a little big problem on Android Studio. A have an object "Sport" that can have multiple lessons. So inside this object there is a list.
public class Sport implements Serializable {
private String cid;
private String cname;
String csportpic;
long ccreatedat;
List<Lesson> lessons;
public Sport() {
}
The object has gets and sets for each element. So the data coming from Firebase in well placed.
In a recycleview I want to display the lessons data and also some variable of the object sport(cname, cid), so I'm passing to the recycleview constructor the object Sport.
Do you have any ideia how to perform a loop through lesson List in a recyclerview? Can it be done inside onBindViewHolder?
Sorry, got it working.
For some reason the first loop was not working correctly. Perhaps the Object was not well written, or the query to the database.
public void onBindViewHolder(#NonNull final CoachVH holder, final int position)
{
for (Lesson lesson:sportlesson.get(position).getLessons())
{
holder.classid.setText(String.valueOf(new SimpleDateFormat("dd-MM-yyyy HH:mm").format(lesson.getLessonTime())));
holder.classname.setText(sportlesson.get(position).getCname());
holder.classaddress.setText(String.valueOf(lesson.getLessonAddress()));
holder.classprice.setText(String.valueOf(lesson.getLessonPrice()));
}
}
I need to have a relatively large number of categories defined (about 30 at start, we'll be adding more). Consider this code:
public class Category {
public static final Category DRESS = new Category("Dress");
public static final Category SKIRT = new Category("Skirt");
...
private static final List<Category> CATEGORIES = Arrays.aslist(DRESS, SKIRT, ...);
private String name;
public Category(String name) {
this.name = name;
}
//Some static public method to iterate over categories
...
I need to have the categories declared and also need a way to iterate over them. I discard reflection because I think it's not a very good practice.
Is declaring a large name of static final fields of the same class and also having them inside a list a good practice? As an alternative, I thought about having a Map<Integer, Category> instead the list, and the fields were integers that would identify each category, so you would get the categories by getting them inside the map. Would this be better in terms of time and space performance?
PS: It's for an android project, if it changes something
Consider this code:
public class Category {
public static final Category DRESS = new Category("Dress");
public static final Category SKIRT = new Category("Skirt");
Yeah this is literally what enums do in the background, so
public enum Category {
DRESS("Dress"),
SKIRT("Skirt"),
...;
private String name;
private Category(String name) {
this.name = name;
}
// Category.values() returns the elements as an array
You should use enum instead of creating an object with new Category("Dress"); because creating an object is expensive than using enum. Java enums are implemented more like classes, so you can change your code seamlessly:
public enum Category {
DRESS("Dress"), SKIRT("Skirt");
private final String name;
Category(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Note:
The constructor for an enum type must be package-private or private access. It automatically creates the constants that are defined at the beginning of the enum body. You cannot invoke an enum constructor yourself.
Read more about enum at Enum Types
I would say using a List is good enough.
You should consider a Map only if you have to look up a
particular Category very frequently via some key property (like an int your case).
If There are no properties or methods in the Category class consider replace them with just Strings.
If new Categories are created at runtime and you want to persist them consider using a DB or File to save the Categories.
Edit: Answering the question in the comment
That would depend on the Category class. If its only purpose is to enumerate all the categories and the class itself does not have any other instance methods or properties then in terms of space complexity an Integer and your Category class is similar (since in a Map integer will be boxed in the Integer class object)
I would still suggest that you use a class called Category and a list if the purpose is only iterating over them and/or using specific instances of the Category class elsewhere in your application eg. Category.SOME_CATEGORY.
The following example is a good use-case
someMethod(Category category) {
// do something
}
versus
someMethod(int category) {
// before doing anything
// lookup this category by an int key
// in the the Map<Integer, Category>
}
The problem with the latter is that you could pass any int which may or may not be a valid key for a category. Using a class gives some bit for extra compile time check. Though you could always use an int def too. But again I would repeat that it all boils down to whether Category class has any instance methods or properties.
For small list, it is okay to use List or Map.
But for a large list, you may want to store them in a database.
Also ArrayList of String will be slightly efficient than using ArrayList of Category
So, I have two models: Document and Item. Table creation and insertion works just perfect. What I want to know is that if I do something like this:
mDaoSession.getDocumentDao().deleteInTx(selectedDocuments);
//or
mDaoSession.getDocumentDao().deleteByKeyInTx(documentIds);
Will any of queries above delete all Items related to this Document or should I do it manually (with additional code)? If not deleting is there any way in GreenDao to accomplish that?
Document.class
public class Document {
#Id(autoincrement = true)
private Long documentId;
#ToMany(referencedJoinProperty = "id")
public List<Item> items;
}
Item.class
public class Item {
private Long id;
}
I've made a simple home screen widget which has two TextView fields and a refresh button. TextViews are loaded from AsyncTask which downloads and parses small XML file. The refresh button calls onUpdate again (using PendingIntent), and eventually AsyncTask again. I have a simple model class XMLValues which can store parsed values from the XML (and which is initialized in the AppWidgetProvider class:
public class XmlValues {
private int mFieldValue1;
public int getFieldValue1() {
return mFieldValue1;
}
public void setFieldValue1(int FieldValue) {
mFieldValue1 = FieldValue;
private int mFieldValue2;
public int getFieldValue2() {
return mFieldValue2;
}
public void setFieldValue2(int FieldValue) {
mFieldValue2 = FieldValue;
}
}
In AsyncTask (I pass in it RemoteViews views, int appWidgetID, AppWidgetManager appWidgetManager) where the XML is downloaded and parsed, the postExecute method looks something like this:
protected void onPostExecute(XmlValues xv) {
if (isCancelled()) {
xv = null;
}
views.setTextViewText(R.id.textView1, xv.getFieldValue1());
views.setTextViewText(R.id.textView2, xv.getFieldValue1());
WidgetManager.updateAppWidget(WidgetID, views);
}
This all works (I load the TextViews with correct values), however I am stuck trying to do the following - since the XML values that I am parsing can potentially change, I would like (for example) to change the color of the TextViews if the new values that come from the new XML are larger then the current ones in the widget. How can I achieve this? I tried looking around but didn't manage to find how to affect the model class object created in the main widget class, from the onPostExecute method from AsyncTask.
You can use static int field where you can store last value:
private static int lastValue1 = -1; // you can use other initial value
private static int lastValue2 = -1;
You can use it then, for example:
if( lastValue1 < xv.getFieldValue1() ) {
lastValue1 = xv.getFieldValue1();
views.setTextViewText(R.id.textView1, xv.getFieldValue1());
}
// the same for second value.
Another solution is to store last value in SharedPreferenced.
I'm sorting an array of custom objects (ListData[]) on two fields. I want it to be sorted by theme, and them by name. I thought i made a nice comparator in the custom object class and that i could use Arrays.sort(ld) to make my code working and sorting my array. But apparently im doing something wrong...
my custom object:
public class ListData implements Comparable<ListData>{
public int venueID;
public String name;
public String photoUrl;
public String tip;
public String theme;
#Override
public int compareTo(ListData ld0) {
return this.venueID- ld0.venueID;
}
public static Comparator<ListData> ListDataThemeAndNameComparator = new Comparator<ListData>() {
#Override
public int compare(ListData ld1, ListData ld2) {
String compareTheme1 = ld1.theme.toUpperCase();
String compareTheme2= ld2.theme.toUpperCase();
String compareName1 = ld1.name.toUpperCase();
String compareName2= ld2.name.toUpperCase();
//ascending
int comp = compareTheme1.compareTo(compareTheme2); // comp themes
if(comp==0){ // same theme
comp= compareName1.compareTo(compareName2); // compare names
}
return comp;
}
};
}
And in my main activity i have:
ListData ld[]= new ListData[jsonResponse.size()];
(some code filling my ListData array)
Arrays.sort(ld, ListData.ListDataThemeAndNameComparator); // compare by theme and then by name
Does anyone know what i'm doing wrong?
I edited my code But still it fails, now on a nullpointerexception on the compareTheme1 = ld1.theme.toUpperCase();. But i am sure my array is not empty, i logged it the line before sorting it and its filled with about 500 items.
Your ListData object should implements Comparable not Comparator interface.
EDIT:
To make things clear, you can sort an array by Array.sort(). To make custom sort, you can specify your comparator in Array.sort(), if you don't do that, array will be sorted in natural order which you can define by implementing Comparable interface. So you have two options how to custom sort:
by using custom comparator and specifying it in Array.sort()
by implementing Comparable interface to your items
I would suggest you to go with implementing Comparable. You save memory by not creating new comparator objects and Comparator is useful if you are comparing objects of different types which is not your case.