Translating iOS Enums to Android - android

I'm busy trying to translate some iOS code to Android code. The iOS code contains Enums, like the following:
typedef NS_OPTIONS(NSUInteger, Traits) {
TraitNumberOne = 1<<0,
TraitNumberTwo = 1<<1,
);
I have never worked with Enums before in Android, and am having trouble interpreting the documentation and examples that are available. How would I translate the above example to Android code?

use this
public enum NS_OPTIONS {
TraitNumberOne (1<<0),
TraitNumberTwo (1<<1);
private final int Option;
public int getOption()
{
return Option;
}
private NS_OPTIONS(int option) {
this.Option= option;
}
}
Use it like this:
int value = NsOptions.TraitNumberOne.getOption();

Java enums are relatively simple, but can be made more complex to fit whatever needs you want to use them for. If you just want the type-safety of an enum, you can just declare the variable names like this:
public enum Traits{
TraitNumberOne,
TraitNumberTwo
}
If you want more advanced features of an enum, it's treated exactly like a class that is instantiated statically for each item in the enum. So, you can have a constructor and input whatever value you want associated with each individual item, like so:
public enum Traits{
TraitNumberOne(0x01),
TraitNumberTwo(0x02),
// future items go here
; // don't forget the semi-colon, which indicates the list of items is ending
// now, create a private variable to store the data
private final int data;
// and the constructor to set the data
private NsOptions(int data){
this.data = data;
}
// now, you can provide an accessor to provide access to the data
public int getData(){
return this.data;
}
}
You can use the above enum like this:
Traits currentOptions = Traits.TraitNumberOne;
int optionsData = currentOptions.getData();

The idea of NS_OPTIONS is to allow all possible combinations of the enumerated values to be represented by one value (this is why bitwise operators are used). In Java, I guess the equivalent would be:
public enum Permission {
TraitNumberOne (0b01),
TraitNumberTwo (0b10);
...
}

We can implement in android like ,
public enum NS_OPTIONS{
TraitNumberOne(1),TraitNumberTwo(2);
private int type;
NS_OPTIONS(int type){
this.type = type;
}
public int getType(){
return type;
}
}
and if you want to use above enum from your class you can use it like,
int i =NS_OPTIONS.TraitNumberOne;//which will return 1
int j =NS_OPTIONS.TraitNumberTwo;//which will return 2;

Related

How to parse an XML file and create objects using found values?

I would like to parse an XML file using Java. I found some tutorials online but no one tells about parsing subtags and using them as objects' attributes.
I tried to use the code found here.
But it doesn't show how to treat tags that are inside other tags. Let me show you an example:
<lotto>
<cig>Z9E1CD9F58</cig>
<strutturaProponente>
<codiceFiscaleProp>00222010654</codiceFiscaleProp>
<denominazione>COMUNE DI PERDIFUMO</denominazione>
</strutturaProponente>
</lotto>
lotto is my main tag, which contains all the data I need. In my code, I created a class called in the same way. Its attributes are the same as the tags contained in the main one (cig, strutturaProponente,...).
I would like strutturaProponente to become a class. I don't know how to parse tags which are inside of tag strutturaProponente as well as the tag cig.
Thank you for your patience and consideration.
Well, let me see if I understood. Would you like the representantion in code of XML, I believe that class would be like something this.
public class Loto
{
private String cig;
public String getCig()
{
return cig;
}
public void setCig(String value){
cig = value;
}
}
public class StrutturaProponente
{
private int codiceFiscaleProp;
private string denominazione;
public int getCodiceFiscaleProp()
{
return cig;
}
public void setCodiceFiscaleProp(int value){
codiceFiscaleProp = value;
}
public String getDenominazione()
{
return denominazione;
}
public void setDenominazione(String value){
denominazione = value;
}
}
I hope have helped.

Where to write logical code for my model?

I've got a ListActivity with about 100 events. (These events are also displayed on a map in another activity.)
So I've my MyListActivity, which handles the list and a MyListAdapter to populate the list that deals with MyEvent-Objects. As model I have a MyEvent-model-Class and a MyEventStorage-Class.
Now have written a method to return an image for an event based on its ID. It does some decisions which image to load, where it gets the image from, loads it and resamples it.
Where should I put this method in best practice?
I don't want to copy it in every activity where it is needed but just in one place.
I'd like to have it in my MyEvent-Class, so I can call myEvent.getImage(); but it somehow feels wrong to put this method inside the model class with all the getters and setters. Is it wrong?
Should I write a helper class containing this method? As a static method? Would this still provide a good performance?
Or maybe create an additional MyImageGetter-object for every MyEvent-object?
Or expand the MyEvent-model with an image-variable and getters/setter and create an extra class that puts the proper image in the model? How would I call that method?
Another solution?
MyEvent.java:
public class MyEvent {
private int id;
private int category;
private String eventname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// other getters and setters
}
MyEventStorage.java:
private static MyEventStorage instance = null;
private List<MyEvent> store;
private MyEventStorage() {
store = new ArrayList<MyEvent>();
}
// get the storage containing the events
public static MyEventStorage getInstance() {
if (instance == null) {
instance = new MyEventStorage();
}
return instance;
}
public List<MyEvent> getStore() {
return store;
}
public void setStore(List<MyEvent> store) {
this.store = store;
}
// Add a Event to the store
public void addEvent(MyEvent myEvent) {
store.add(myEvent);
}
// Remove a Event from the store
public void removeEvent(MyEvent myEvent) {
store.remove(myEvent);
}
}
The method I want to integrate:
Image getImageById(int id) {
// decide which image to load based on the events id
// decide where to load the image from
// check if image available
// load image if available else load placeholder image
// resample image
return image;
}
Thank you advance!
I think your last bullet point is spot on.
If the Image is in fact a property of MyEvent, it makes sense to add an instance variable to that class. You shouldn't include the logic for retrieving an event's image from a datasource in the model, but rather use a static utility method to load this property.
Your getImageById method looks like it has to do a decent amount of work to retrieve the image from wherever it is stored. I think it would make the most sense to create a utility class (along the lines of ImageRetriever) like you mentioned in order to perform the actual retrieval of the image. This prevents you from having to copy the method to multiple places. Performance should not be a concern either, as you'll never have to instantiate this class.
The code could look something like this:
public class MyEvent {
private int id;
private int category;
private String eventname;
private Image image;
public MyEvent(int id...) {
// initialize instance vars
setImageFromRetriever();
}
public void setImage(Image image) {
this.image = image;
}
public void setImageFromRetriever() {
// optional null check if you don't want to reload images
setImage(ImageRetriever.getImageById(this.id));
}
}

Android - can you have multiple variable types for single method() parameter?

Can you have two or more variable types for a single method() parameter?
At the moment, you can do:
method(String string, int int, etc...) {
}
What if you wanted to do something like
method(String or int stringint) {
}
can this be done?
I'd do it like this:
private boolean function(String str){
// Do stuff
}
private boolean function(int intStr){
String str = convertToString(intStr);
return function(str);
}
Avoids unnecessary classes, etc.
Just overload the method signature.
public void someMethod(string argument){
}
public void someMethod(int argument){
}
If you have to stick to one single parameter you can use a wrapper, which contains two fiels:
public class MyWrapper
{
String stringValue;
int intValue;
}
public void someMethod(MyWrapper arg)
{
if(arg.stringField != null)
{
// do something with the string
}
/* checking for the default value 0 makes no sense here, since it
might be a value you actually want to pass - The first conditional
statement covers the case you actually only passed a string
*/
else
{
// do something with the int
}
}

Android, Best way to provide app specific constants in a library project?

I am creating a library project for a number of android apps.
The apps all have some common functionality that I wish to include in the library project but the library project functions require use of application specific constants
So I am looking for a way to provide the library functions with the names of the constants and allow each app to define them
An example of a specific app constant and how it is used within the library project
public class AppConstants {
public static final long APP_ID = 6;//Needs to be set for each app
}
public static long getCurrentAppId(Context context) {
return getLongPreference(context, CURRENT_APP_ID_KEY, AppConstants.APP_ID);
}
This is just one example of approximately 60 constants that need to be defined for each app for a large number of library functions
Obviously I would normally just import/include the project specific app_constants.java file but this is not possible in the library project files as it hasn't got a clue about the specific applications (rightly so)
So what is the best way to have each specific app override the constants?
Update
I took a long time deciding on which of the superb answers I have been provided with best suited my needs (Thanks everyone) In the end I chose the xml solution. I don't particularly like it because it clutters up my apps resources and I did seriously consider using the interface solution but the xml solution does work nicely
Option #1
Extend your AppConstants class in each project
Better Option#2
Use XML resources to define the constants
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="integer" name="app_id" format="integer">6</item>
</resources>
then you can retrieve them by
Context.getResources().getInteger(R.integer.app_id);
add the xml file to your resources in each project with only the values you need different
I don't know of a great schema to do that but it would certainly work this way:
define some base class in your library
// class, enum or whatever you want it to be.
class BaseConstants {
// use some real singleton instead
public static final BaseConstants instance = new BaseConstants();
// define those values - sadly static inheritance does not work
private static final int APP_ID = 0;
private static final int CURRENT_APP_ID_KEY = 24;
// so we have to do that via methods
protected int getAppId() {
return APP_ID;
}
protected int getAppIdKey() {
return CURRENT_APP_ID_KEY;
}
}
let each Activity that wants something custom implement that
class App1Constants extends BaseConstants {
public static final App1Constants instance = new App1Constants();
private final static int APP_ID = 1;
// want a different APP_ID here.
protected int getAppId() {
return APP_ID;
}
// getAppIdKey not implemented here, uses default
}
Use that class as context to the constants for your library
class Library {
public static long getCurrentAppId(Context context, BaseConstants settings) {
return getLongPreference(context, settings.getAppIdKey(), settings.getAppId());
}
}
Activities would be like so
class myActivity extends Activity {
// each Activity can implement it's own constants class and overwrite only some values
private static final BaseConstants CONSTANTS = App1Constants.instance;
private void whatever() {
long appId = Library.getCurrentAppId(this, CONSTANTS);
}
}
class myActivity2 extends Activity {
// or could just use the default ones
private static final BaseConstants CONSTANTS = BaseConstants.instance;
private void whatever() {
long appId = Library.getCurrentAppId(this, CONSTANTS);
}
}
That schema is kind of ugly but it would work at least
Define them as enum's in your library project, like
public enum Planet { MERCURY, VENUS, MARS }
Android proper takes another approach, the dreaded constant interface, like,
interface Planets {
static final int MERCURY = 1;
static final int VENUS = 2;
...
}
However, this is a well-known Java anti-pattern (constant interface, and is covered in detail in Effective Java, I quote,
The constant interface pattern is a poor use of interfaces. That a
class uses some constants internally is an implementation detail.
Implementing a constant interface causes this implementation detail to
leak into the class’s exported API. It is of no consequence to the
users of a class that the class implements a constant interface. In
fact, it may even confuse them. Worse, it represents a commitment: if
in a future release the class is modified so that it no longer needs
to use the constants, it still must implement the interface to ensure
binary compatibility. If a nonfinal class implements a constant
interface, all of its subclasses will have their namespaces polluted
by the constants in the interface.
If you need the constants to have int values for some reason, and calling toString() on the enum isn't sufficient, you can give the enum's a extra information like,
public enum ZipCode {
LYNNWOOD(98036), SAN_JOSE(95112), ...;
private int zipCode;
private ZipCode(int zipCode) { this.zipCode = zipCode; }
public int getZipCode() { return zipCode; }
}
Note that enum's are slightly less performing than integer constants, but from a code organization and clarity perspective they are far superior.

Passing enum or object through an intent (the best solution)

I have an activity that when started needs access to two different ArrayLists. Both Lists are different Objects I have created myself.
Basically I need a way to pass these objects to the activity from an Intent. I can use addExtras() but this requires a Parceable compatible class. I could make my classes to be passed serializable but as I understand this slows down the program.
What are my options?
Can I pass an Enum?
As an aside: is there a way to pass parameters to an Activity Constructor from an Intent?
This is an old question, but everybody fails to mention that Enums are actually Serializable and therefore can perfectly be added to an Intent as an extra. Like this:
public enum AwesomeEnum {
SOMETHING, OTHER;
}
intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);
AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");
The suggestion to use static or application-wide variables is a really bad idea. This really couples your activities to a state managing system, and it is hard to maintain, debug and problem bound.
ALTERNATIVES:
A good point was noted by tedzyc about the fact that the solution provided by Oderik gives you an error. However, the alternative offered is a bit cumbersome to use (even using generics).
If you are really worried about the performance of adding the enum to an Intent I propose these alternatives instead:
OPTION 1:
public enum AwesomeEnum {
SOMETHING, OTHER;
private static final String name = AwesomeEnum.class.getName();
public void attachTo(Intent intent) {
intent.putExtra(name, ordinal());
}
public static AwesomeEnum detachFrom(Intent intent) {
if(!intent.hasExtra(name)) throw new IllegalStateException();
return values()[intent.getIntExtra(name, -1)];
}
}
Usage:
// Sender usage
AwesomeEnum.SOMETHING.attachTo(intent);
// Receiver usage
AwesomeEnum result = AwesomeEnum.detachFrom(intent);
OPTION 2:
(generic, reusable and decoupled from the enum)
public final class EnumUtil {
public static class Serializer<T extends Enum<T>> extends Deserializer<T> {
private T victim;
#SuppressWarnings("unchecked")
public Serializer(T victim) {
super((Class<T>) victim.getClass());
this.victim = victim;
}
public void to(Intent intent) {
intent.putExtra(name, victim.ordinal());
}
}
public static class Deserializer<T extends Enum<T>> {
protected Class<T> victimType;
protected String name;
public Deserializer(Class<T> victimType) {
this.victimType = victimType;
this.name = victimType.getName();
}
public T from(Intent intent) {
if (!intent.hasExtra(name)) throw new IllegalStateException();
return victimType.getEnumConstants()[intent.getIntExtra(name, -1)];
}
}
public static <T extends Enum<T>> Deserializer<T> deserialize(Class<T> victim) {
return new Deserializer<T>(victim);
}
public static <T extends Enum<T>> Serializer<T> serialize(T victim) {
return new Serializer<T>(victim);
}
}
Usage:
// Sender usage
EnumUtil.serialize(AwesomeEnum.Something).to(intent);
// Receiver usage
AwesomeEnum result =
EnumUtil.deserialize(AwesomeEnum.class).from(intent);
OPTION 3 (with Kotlin):
It's been a while, but since now we have Kotlin, I thought I would add another option for the new paradigm. Here we can make use of extension functions and reified types (which retains the type when compiling).
inline fun <reified T : Enum<T>> Intent.putExtra(victim: T): Intent =
putExtra(T::class.java.name, victim.ordinal)
inline fun <reified T: Enum<T>> Intent.getEnumExtra(): T? =
getIntExtra(T::class.java.name, -1)
.takeUnless { it == -1 }
?.let { T::class.java.enumConstants[it] }
There are a few benefits of doing it this way.
We don't require the "overhead" of an intermediary object to do the serialization as it's all done in place thanks to inline which will replace the calls with the code inside the function.
The functions are more familiar as they are similar to the SDK ones.
The IDE will autocomplete these functions which means there is no need to have previous knowledge of the utility class.
One of the downsides is that, if we change the order of the Emums, then any old reference will not work. This can be an issue with things like Intents inside pending intents as they may survive updates. However, for the rest of the time, it should be ok.
It's important to note that other solutions, like using the name instead of the position, will also fail if we rename any of the values. Although, in those cases, we get an exception instead of the incorrect Enum value.
Usage:
// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()
You can make your enum implement Parcelable which is quite easy for enums:
public enum MyEnum implements Parcelable {
VALUE;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeInt(ordinal());
}
public static final Creator<MyEnum> CREATOR = new Creator<MyEnum>() {
#Override
public MyEnum createFromParcel(final Parcel source) {
return MyEnum.values()[source.readInt()];
}
#Override
public MyEnum[] newArray(final int size) {
return new MyEnum[size];
}
};
}
You can then use Intent.putExtra(String, Parcelable).
UPDATE: Please note wreckgar's comment that enum.values() allocates a new array at each call.
UPDATE: Android Studio features a live template ParcelableEnum that implements this solution. (On Windows, use Ctrl+J)
You can pass an enum through as a string.
public enum CountType {
ONE,
TWO,
THREE
}
private CountType count;
count = ONE;
String countString = count.name();
CountType countToo = CountType.valueOf(countString);
Given strings are supported you should be able to pass the value of the enum around with no problem.
For passing an enum by intent, you can convert enum into integer.
Ex:
public enum Num{A ,B}
Sending(enum to integer):
Num send = Num.A;
intent.putExtra("TEST", send.ordinal());
Receiving(integer to enum):
Num rev;
int temp = intent.getIntExtra("TEST", -1);
if(temp >= 0 && temp < Num.values().length)
rev = Num.values()[temp];
Best regards.
:)
If you really need to, you could serialize an enum as a String, using name() and valueOf(String), as follows:
class Example implements Parcelable {
public enum Foo { BAR, BAZ }
public Foo fooValue;
public void writeToParcel(Parcel dest, int flags) {
parcel.writeString(fooValue == null ? null : fooValue.name());
}
public static final Creator<Example> CREATOR = new Creator<Example>() {
public Example createFromParcel(Parcel source) {
Example e = new Example();
String s = source.readString();
if (s != null) e.fooValue = Foo.valueOf(s);
return e;
}
}
}
This obviously doesn't work if your enums have mutable state (which they shouldn't, really).
It may be possible to make your Enum implement Serializable then you can pass it via the Intent, as there is a method for passing it as a serializable. The advice to use int instead of enum is bogus. Enums are used to make your code easier to read and easier to maintain. It would a large step backwards into the dark ages to not be able to use Enums.
Most of the answers that are using Parcelable concept here are in Java code. It is easier to do it in Kotlin.
Just annotate your enum class with #Parcelize and implement Parcelable interface.
#Parcelize
enum class ViewTypes : Parcelable {
TITLE, PRICES, COLORS, SIZES
}
about Oderik's post:
You can make your enum implement Parcelable which is quite easy for enums:
public enum MyEnum implements Parcelable {
...
}
You can than use Intent.putExtra(String, Parcelable).
If you define a MyEnum variable myEnum, then do intent.putExtra("Parcelable1", myEnum), you will get a "The method putExtra(String, Parcelable) is ambiguous for the type Intent" error message.
because there is also a Intent.putExtra(String, Parcelable) method, and original 'Enum' type itself implements the Serializable interface, so compiler does not know choose which method(intent.putExtra(String, Parcelable/or Serializable)).
Suggest that remove the Parcelable interface from MyEnum, and move the core code into wrap class' Parcelable implementation, like this(Father2 is a Parcelable and contain an enum field):
public class Father2 implements Parcelable {
AnotherEnum mAnotherEnum;
int mField;
public Father2(AnotherEnum myEnum, int field) {
mAnotherEnum = myEnum;
mField = field;
}
private Father2(Parcel in) {
mField = in.readInt();
mAnotherEnum = AnotherEnum.values()[in.readInt()];
}
public static final Parcelable.Creator<Father2> CREATOR = new Parcelable.Creator<Father2>() {
public Father2 createFromParcel(Parcel in) {
return new Father2(in);
}
#Override
public Father2[] newArray(int size) {
return new Father2[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mField);
dest.writeInt(mAnotherEnum.ordinal());
}
}
then we can do:
AnotherEnum anotherEnum = AnotherEnum.Z;
intent.putExtra("Serializable2", AnotherEnum.X);
intent.putExtra("Parcelable2", new Father2(AnotherEnum.X, 7));
you can use enum constructor for enum to have primitive data type..
public enum DaysOfWeek {
MONDAY(1),
TUESDAY(2),
WEDNESDAY(3),
THURSDAY(4),
FRIDAY(5),
SATURDAY(6),
SUNDAY(7);
private int value;
private DaysOfWeek(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static final SparseArray<DaysOfWeek> map = new SparseArray<DaysOfWeek>();
static
{
for (DaysOfWeek daysOfWeek : DaysOfWeek.values())
map.put(daysOfWeek.value, daysOfWeek);
}
public static DaysOfWeek from(int value) {
return map.get(value);
}
}
you can use to pass int as extras then pull it from enum using its value.
I like simple.
The Fred activity has two modes -- HAPPY and SAD.
Create a static IntentFactory that creates your Intent for you. Pass it the Mode you want.
The IntentFactory uses the name of the Mode class as the name of the extra.
The IntentFactory converts the Mode to a String using name()
Upon entry into onCreate use this info to convert back to a Mode.
You could use ordinal() and Mode.values() as well. I like strings because I can see them in the debugger.
public class Fred extends Activity {
public static enum Mode {
HAPPY,
SAD,
;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.betting);
Intent intent = getIntent();
Mode mode = Mode.valueOf(getIntent().getStringExtra(Mode.class.getName()));
Toast.makeText(this, "mode="+mode.toString(), Toast.LENGTH_LONG).show();
}
public static Intent IntentFactory(Context context, Mode mode){
Intent intent = new Intent();
intent.setClass(context,Fred.class);
intent.putExtra(Mode.class.getName(),mode.name());
return intent;
}
}
I think your best bet is going to be to convert those lists into something parcelable such as a string (or map?) to get it to the Activity. Then the Activity will have to convert it back to an array.
Implementing custom parcelables is a pain in the neck IMHO so I would avoid it if possible.
Consider Following enum ::
public static enum MyEnum {
ValueA,
ValueB
}
For Passing ::
Intent mainIntent = new Intent(this,MyActivity.class);
mainIntent.putExtra("ENUM_CONST", MyEnum.ValueA);
this.startActivity(mainIntent);
To retrieve back from the intent/bundle/arguments ::
MyEnum myEnum = (MyEnum) intent.getSerializableExtra("ENUM_CONST");
If you just want to send an enum you can do something like:
First declare an enum containing some value(which can be passed through intent):
public enum MyEnum {
ENUM_ZERO(0),
ENUM_ONE(1),
ENUM_TWO(2),
ENUM_THREE(3);
private int intValue;
MyEnum(int intValue) {
this.intValue = intValue;
}
public int getIntValue() {
return intValue;
}
public static MyEnum getEnumByValue(int intValue) {
switch (intValue) {
case 0:
return ENUM_ZERO;
case 1:
return ENUM_ONE;
case 2:
return ENUM_TWO;
case 3:
return ENUM_THREE;
default:
return null;
}
}
}
Then:
intent.putExtra("EnumValue", MyEnum.ENUM_THREE.getIntValue());
And when you want to get it:
NotificationController.MyEnum myEnum = NotificationController.MyEnum.getEnumByValue(intent.getIntExtra("EnumValue",-1);
Piece of cake!
Use Kotlin Extension Functions
inline fun <reified T : Enum<T>> Intent.putExtra(enumVal: T, key: String? = T::class.qualifiedName): Intent =
putExtra(key, enumVal.ordinal)
inline fun <reified T: Enum<T>> Intent.getEnumExtra(key: String? = T::class.qualifiedName): T? =
getIntExtra(key, -1)
.takeUnless { it == -1 }
?.let { T::class.java.enumConstants[it] }
This gives you the flexibility to pass multiple of the same enum type, or default to using the class name.
// Add to gradle
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
// Import the extension functions
import path.to.my.kotlin.script.putExtra
import path.to.my.kotlin.script.getEnumExtra
// To Send
intent.putExtra(MyEnumClass.VALUE)
// To Receive
val result = intent.getEnumExtra<MyEnumClass>()
Don't use enums. Reason #78 to not use enums. :) Use integers, which can easily be remoted through Bundle and Parcelable.

Categories

Resources