I saw the video(https://www.youtube.com/watch?v=Hzs6OBcvNQE) posted from google about price of enum and I'm convinced that enum cost more and has performance issue.
However, what about when I need to contain multiple information in an enum? Do I have to create intdef and stringdef to map the message?
Ie.
public enum Error{
NETWORK(1, "Network error!"),
STACK_OVER_FLOW(2, "Stack over flow error!");
final int mValue;
final String mMessage;
Error(int value, String message){
mValue = value;
mMessage = message;
}
public void getMessage(){
return mMessage;
}
public void getValue(){
return mValue
}
}
It is true that enums have that memory footprint, but just if are heavily using them, or sub using them, like comparisions or else, but if you're using such functionality like the one in your code, it's more than justified to work with them, in case you want to totally avoid enums, you can change this to a class.
Related
I have a pretty simple Enum that I am using throughout my application for Gender and I need to have a settings page where the user can change it, but I can't find any way to use an Enum in a ListPreference. I am using a PreferenceFragment to build the Preferences Screen, but I can't find a way to use the Enum I have as the entries and entryValues for the ListPreference.
The enum is very simple, just...
public enum Gender implements EnumSpinner {
MALE("Male", 0),
FEMALE("Female", 1),
NONE("Prefer not to say", -1);
private static SparceArray<Gender> genderMap = new SparceArray<>();
static {
for(Gender gender : Gender.values()) {
genderMap.put(gender.getValue(), gender);
}
}
private String name;
private int value;
Gender(String name, int value) {
this.name = name;
this.value = value;
}
public static Gender getGender(int val) { return genderMap.get(val); }
#Override
public String toString() { return name; }
public String getName() { return name; }
public int getValue() { return value; }
}
Is it possible to use in a ListPreference or am I going to have to create 2 string arrays in the strings.xml file and just use it that way?
SideNote, EnumSpinner is just an interface that allows me to use the enum in a spinner.
Please check in the google developers youtube channel, Android Performance Matters there is a video explaining why you would prefer not using enums in Android, there are other ways to get the same functionality.
Android has a Framework for Settings/Preferences, you can find an excellent tutorial here.
Buuilding Settings Screen Android
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
GreenDAO is searching for getters and setters with the "m" prefix included in the name in its generated classes.
For example, I've set the entity to not generate any getters and setters but it still looks for, let's say, getMDate() for my private Date mDate, instead of my manually created getDate() method. Same goes for setters.
This is just breaking my adherence to the Android Code Style Guidelines.
Is there any way to configure greenDAO to use the code style standards that I've set out in Android Studio when it generates code?
EDIT: Just to make things clearer, I've added some code to get my point across. I wrote the above question half knocked out on antihistamines due to having chronic hayfever while I was trying to work and just wanted to get to sleep so I apologise if it wasn't enough to work with.
#Entity(generateConstructors = false, generateGettersSetters = false)
public class Day {
#Id
private long mId;
#Unique
#NotNull
private Date mDate;
#ToMany(referencedJoinProperty = "mDayId")
private List<Goal> mGoals;
public Day(long id) {
this.mId = id;
mGoals = new ArrayList<Goal>();
}
public Day(long id, Date date) {
this.mId = id;
this.mDate = date;
}
public long getId() {
return mId;
}
public void setId(long id) {
mId = id;
}
public Date getDate() {
return mDate;
}
public void setDate(Date date) {
mDate = date;
}
public List<Goal> getGoals() {
return mGoals;
}
public void setGoals(List<Goal> goals) {
mGoals = goals;
}
}
Above is my Day class. As you can see I've disabled generation of the getters and setters in the #Entity annotation, and put my own in there. I've set up Android Studio to take the "m" into consideration when I use alt+enter to create getters and setters for each of my fields.
public Date getMDate() {
return mDate;
}
public void setMDate(Date mDate) {
this.mDate = mDate;
}
Here is an example of the getters and setters that greenDAO generates for my code given the field private Date mDate. This is breaking the code style guidelines in that the local variables include the "m" prefix and also that the method names include it as well (maybe a bit of a nit-pick there, but you can set up Android Studio so it doesn't do that which makes me think it shouldn't be like that).
With my getters and setters there, greenDAO still thinks the getters and setters are missing, which results in them being added twice. Once as the ones I put in, and another as what you see above. This also results in the generation of the code below.
#Override
protected final void bindValues(DatabaseStatement stmt, Day entity) {
stmt.clearBindings();
stmt.bindLong(1, entity.getMId());
stmt.bindLong(2, entity.getMDate().getTime());
}
#Override
protected final void bindValues(SQLiteStatement stmt, Day entity) {
stmt.clearBindings();
stmt.bindLong(1, entity.getMId());
stmt.bindLong(2, entity.getMDate().getTime());
}
Here is some of the code from the class DayDao which is generated from greenDAO. It's still using the names for the getters (and also setters) that it would have used to generate its own getters and setters (getMDate() instead of getDate()) if I didn't disable their generation on the Day entity class. I can't change this code because it just switches back the next time I build the project, and there is my problem.
My question is: how can I get greenDAO to take the "m" prefix thing into consideration when it generates its code and get it to use the getters and setters that I have set out myself? Or even get it to generate getters and setters itself without the "m" being included in the name and local variables?
The solution that I decided to use for this ended up being rather disappointing.
It involved just making my properties all public instead of private. Still conforming to the code style, these properties would no longer use the m prefix ... or any prefix, for that matter. It's not a very satisfactory solution as now my data can be accessed and set directly, just for a simple naming convention to be conformed to.
I (personally) disagree with people saying that using naming conventions hurts readability. If you structure your code well enough and give enough of a description in Javadoc comments and the like, you'll know exactly what something is doing. Having said that, if using the conventions is going to create such code as in my question above, then I guess that this is a situation where it does, and a reason not to use the code style in my other projects and still stick to the access that I want for my data.
I've been trying to add Realm in my Android app. Their docs are pretty well explained & easy to follow. But it fails to explain this one particular area. I'm unable to figure out the practical use for the #Ignore annotation. I know that fields under this annotation are not persisted.
Can someone please share a few use cases. Also I wanted to know the scope of such fields. I mean, if I set an #Ignore field to some value, would that value be available to the other classes in my app for that particular launch session. If yes, then how do we access it? If no (which I guess is the case), then why do we need such a field anyway?
I've searched here and on web but couldn't find the relevant information. If out of my ignorance, I've missed upon some resource, please guide me to it.
Thanks.
Accordingly to the official documentation (see https://realm.io/docs/java/latest/) #Ignore is useful in two cases:
When you use GSON integration and your JSON contains more data than you want to store, but you still would like to parse it, and use right after.
You can't create custom getters and setter in classes extending RealmObject, since they are going to be overridden. But in case you want to have some custom logic anyway, ignored fields can be used as a hack to do that, because Realm doesn't override their getter & setters. Example:
package io.realm.entities;
import io.realm.RealmObject;
import io.realm.annotations.Ignore;
public class StringOnly extends RealmObject {
private String name;
#Ignore
private String kingName;
// custom setter
public void setKingName(String kingName) { setName("King " + kingName); }
// custom getter
public String getKingName() { return getName(); }
// setter and getter for 'name'
}
Ignored fields are accessible only from the object they were set in (same as with regular objects in Java).
UPDATE: As the #The-null-Pointer- pointed out in the comments the second point is out of date. Realm now allows having custom getters and setters in Realm models.
Here's a couple of real-world use cases:
1 - Get user's fullname:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private String fullName;
public String getFullName() {
return getFirst() + " " + getLast();
}
Get JSON representation of object:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private JSONObject Json;
public JSONObject getJson() {
try {
JSONObject dict = new JSONObject();
dict.put("first", getFirst());
dict.put("last", getLast());
return dict;
} catch (JSONException e) {
// log the exception
}
return null;
}
I've found it useful to define field names for when I am querying. For example
User.java
public class User extends RealmObject {
#Index
public String name;
#Ignore
public static final String NAME = "name";
}
And then later on I can do something like:
realm.where(User.class).equalTo(User.NAME, "John").findFirst();
This way if the schema changes from say name to id I don't have to hunt down every occurrence of "name".
Please see the the official documentation about #Ignore annotation:
The annotation #Ignore implies that a field should not be persisted to disk. Ignored fields are useful if your input contains more fields than your model, and you don’t wish to have many special cases for handling these unused data fields.
I have a project that I have to design an array of coins and work with it. My GUI looks like this - http://i.imgur.com/eRzN3Sb.png
I want to be able to load the appropriate image from the coinArray for each coin. basically i want to be able to say coinView.setBackgroundResource(coinArray[x].image) i assume i need to somehow use a drawable object and i was hoping its possible to include it in my enum class. the enum class looks like
public enum Currency {
Penny(1), Nickel(5), Dime(10), Quarter(25);
private int value;
private Currency(int value) {
this.value = value;
}
}
Each coin in the array has a currency value so i can compute them. I'd like to add a drawable or some other object that will allow me to refernce the correct image for each coin.
Thank you
public enum Currency {
Penny(1,R.drawable.xxx), Nickel(5,R.drawable.yyy),...;
private int value;
private int image
private Currency(int value,int drawableId) {
this.value = value;
this.image=drawableId;
}
public int getImage(){
return image;
}
}
There are many ways you can do this. This is one of them. to use it:
coinView.setImageResource(coinArray[x].getImage());