I've checked the suggested solutions and can't find my answer. If the answer is out there, then I'm sorry for posting it again.
I'm consuming a wcf rest service.
In my test activity I do;
private final static String SERVICE_URI = "http://10.0.2.2/Service1.svc";
This will eventually be used in various activities.
So what I want to do is: private final static String SERVICE_URI = [CONSTANT]
so that if I need to re-point the service somewhere else, a single code update will result in dependent activities pointing to the correct location, allowing them to work, rather than having to update each activity.
So: how / where would I create such a constant in Android, and how would I reference it?
Many thanks any help.
The alternative to String Resources, you could do it the via creating Constants class and put your constant value there. This method is not exactly specific to Android, but have been a practice that is used by the Java community frequently.
public class Constants {
public final static String SERVICE_URI = "http://10.0.2.2/Service1.svc";
}
And refer it in other Activity/classes as Constants.SERVICE_URI. If you use this approach, you can use it anywhere even when Context or Application is not available for you.
From what you describe it sounds like you need to look at String Resources.
You can access them from any component in your Android app at any time and they're effectively 'constant' at build time.
EDIT Just to expand on the use of resources...
...take a look at Dororo's answer. All resources (strings, images / drawables and even UI elements such as Buttons etc) are accessed using 'resource IDs'. Any resId, i.e. R.blah is an int representing the resource. As such, it needs to be fetched in the correct way.
With UI elements we use findViewById(...) and with strings we use getString(...) as in Dororo's example.
My point was that the strings are constant at build time so it isn't necessary to declare any variable as final static that represents a string resource as part of any class such as an Activity because you can access any string using the Context.getString(...) method as shown in the link.
When would you want to change this string?
If you want to change it dynamically without issuing updates to the program, you'll want to probably set it globally and then create functions to edit it which can be called whenever you wish to change the address.
If you're happy to only ever change it when the program is updated (which not all users will necessarily do remember) then you'll want to set it as a string resource or just set it globally and slap on final. To access the string from a String resource use:
context.getString(R.string.resource_name)
application.getString(R.string.resource_name)
To create a string resource, open /res/values/strings.xml and create a new string using:
<string name="resource_name">whatever web address here</string>
Related
I need to access a few of my custom objects in different activities of my application. For this purpose and for the sake of accessibility I have been using static properties for moving data from an activity to another.
For example I have the following class:
public class TrackItem {
public String title, imageUrl, mediaUrl, type, artist, desc;
public static TrackItem track;
}
And for starting an activity:
TrackItem.track = items.get(i); // 'items' is an arraylist defined elsewhere
Intent trackActivity = new Intent(c, TrackActivity.class);
startActivity(trackActivity);
And now inside the TrackActivity I can easily access TrackItem.track and use it's properties.
I just need to know if I'm making a mistake or not? Is there any better way to do this?
The android way of dealing with that problem is to make your class
Parcelable
and pass it with the intent from one activity to another.
If you are initializing your static variables in an activity be aware of loosing data, because in android activity can be destroyed at any point after its state changed to pause. Moreover, your static variables can be erased if the entire application is killed by the system, that is happening rather frequently. Then you'll get the
NullPointerException
trying to access your data.
If you really want to use static members handle their initialization in the
Application
class constructor, so they will be recreated on the start of your application, being killed.
But in general it is not a good practice in android.
I would say it is OK in certain cases, but there might be other more suitable solutions.
You could have a central data store class that uses the singleton principle and therefore would be accessible from everywhere. You would add the item id to the Intent for the new Activity. Then, with the id, you could get the item from the data store.
You could also make the item serializable and just add it to the Intent.
One thing to keep in mind when using static members is that it could lead to a memory leak. Static members are related to the class and are therefore only garbage collected if you either set them to null, or the whole app gets killed and the classloader unloads this specific class.
In general, this is an unsafe practice because it is difficult to keep track of who is manipulating its data. It is much safer to use static variables for bookkeeping information, such as an ID which you can use to go look up the appropriate TrackItem (e.g. in an SQLite database), which is its own object and does not have the chance of something else editing it when it shouldn't be. It terms of OOP, using static variables as shared data breaks encapsulation.
If you are looking to send data around the app, it would be much better to do so either with intents, as others are saying, or with SharedPreferences. Both have the advantage that you are dealing with only one instance of the object at any given time, SharedPreferences have the added advantage of keeping the data around after the app has been killed, so that users can resume with the same track that was playing when they closed the app. And both of these are safer than using static members as shared data fields.
In an Android application, is it bad practice to store objects in static fields in these cases?
Application data. Is it bad to keep application data in static variables in a class while the application is running? Currently, I'm storing the data in an instance variable in my Application class. Then classes that need the data can obtain the data from the Application.
Context's etc. Is it bad practice to store a Context (e.g. a reference to an Activity or an Application) in a static field? This can be used in a class that needs e.g. a LayoutInflater or resources. Currently, I am passing the Contexts to methods needing them as arguments.
Yes and Yes. :)
Static Fields. There are a lot of problems with excessive usage of Static fields. Not only they are slower to access by an interesting margin, but also they are prone to be destroyed overnight by Android, and it's usually hacky to check for their references all over the place or fill your getter/setters with if (sSomeStatic == null) { return new SomeStatic()}. It's ok to store a static reference to a class called (for example) ApplicationData where you store some values, hey, we NEED some globals every now and then, but it's so easy to abuse it, that I frown every time I inspect new Android devs' source code.
Yes, store your Application instance in a singleton pattern and use it, but don't add 200 static fields to your Application implementation just because you can do YOURAPP.getInstance().SomeLazyValueYouAddedHere();
That is bad. It leads to bad practices and it will be slower than having a good design where you access hard references.
I could go on forever but there are a lot of StackOverflow discussions (some heated!) about this. If you are here, I'm assuming you're asking for experience; I've been doing Android for a couple of years in different projects and my experience has always been that the less Static, the merrier.
Now the context… oh the Context. Don't store the Context in a hard reference, ever. Or you will leak memory. An activity has references to View and a multitude of other things. If you store the Context, you're storing the activity and things go bad from there. Learn to pass the Context around, use the Application Context whenever possible and if you need to pass it around, do it for very good reasons. Most of the time the App context is enough for getting resources, strings, etc.
If you're going to store the Context, always store context.getApplicationContext(); Never store a static activity context. You can google this too and StackOverflow has some good answers.
If you can afford one and only one Android book, get the BNR one. Even though Android may release new SDKs every now and then, the concepts are completely valid and the patterns the author uses are the right way to deal with Activities, Contexts, Fragments, etc.
UPDATE Your Application should look like this:
public class YourApp extends Application {
private static YourApp sInstance;
public YourApp() {
super();
sInstance = this;
}
public static YourApp getInstance() {
return sInstance;
}
}
And in that case, yes, you are getting the same Static reference to the same App Context.
There are a few immutable variables to be set and used throughout the entire project. Is it correct if I simple have a class with a couple of static fields in it that I can call? Is there a better approach?
The context includes both "regular" Java projects (e.g. web service kind of thing) and Android projects. Example of what I am doing at the moment:
class Settings {
public static final String APP_TAG = "Some name";
public static final String URI = "http://43.12.323.12:8080/Server";
public static final int MAX_NUMBER_OF_PIGEONS = 25;
}
Would loading some proj_name.config be that much better? As of now, I see this alternative as extra work and no benefits.
Yes, it is fine to consolidate "global constants" into a single object like you are doing, but you may want to consider placing all these constants in an XML resource, which allows greater flexibility in customization, localization, etc.
Note that if you elect to go the XML resource file, you will have to pass a context to any consumer of these constants.
You have at least two possible ways of doing this in Android.
The use of SharedPreferences. This way you can save all the information you need in memory. Another
The resource files that are created in your Android project (such as Strings.xml) could help you aswell to keep a some information in a static way in your app.
My application has a service and my MainActivity has a static variable :
public static boolean appIsPlaying = false;
And my service code is something like this :
MainActivity.appIsPlaying = false;
This code works well but I'm not sure that it's a true way. So, would you help me if there is a problem with this solution?
Thanks
I don't really agree with the people who say let's just use getters and setters for everything, and that's the solution. Your solution is simple, but effective. There are no problems with this way of communication between a service and an activity per se. This isn't some public API, so using public fields isn't a definite no-no.
Problems can only arise if you have certain requirements which you have to fulfill. This from of interaction is the simplest, therefore it can't do much. For example, if you want to listen to the event of changing the value, then you will have a problem because you just set the value and don't notify the activity.
If that's the case, then you can bind to the service, and implement more complex interaction. Listening to the value changes could be done by storing listeners in the service and notifying them when changes happen.
There is not really the way to do it, there are more appropriate ones and less so. You have to choose one of them depending on your needs.
Put your static variable in a utility class and create static getters and setters with required validations. Making the class Single Instance is also preferred but what you are doing right is not without problems.
Introduction:
I'm working on an API which provides access to Picasa, Flickr and some other image services.
I have a class WebAlbum (it provides access to nested photos, albums if allowed, and some meta information).
My API allows the user not only to read albums but it also allows them to create new albums. In the general case, in order to create new album, the API user should use a factory method, which creates an album and then call the method WebGallery#addAlbum (newAlbum).
But Flickr doesn't allow creation of empty albums, it requires at least one predefined photo in any new album (to make nice album preview probably). In Flickr terms this first photo is called the Primary Photo. So in order to create an album for Flickr, user should use a factory method, then add an image to the new album, and then call WebGallery#addAlbum (newAlbum).
Problem:
At the moment WebAlbum class has this method
public interface WebAlbum {
...
public boolean requiresPrimaryPhoto ();
}
I can't leave this name because PrimaryPhoto is just a Flickr term. I can change it to
public interface WebAlbum {
...
//with spaces: requires one added photo to create new album
public boolean requiresOneAddedPhotoToCreateNewAlbum ();
}
Please suggest a shorter name which has the same meaning.
boolean isEmptyAlbumAllowed
public boolean needsDefault;
or, more descriptive
public boolean needsDefaultImg;
EDIT
Another question you should ask yourself is if this property even should be exposed. If you want to make the experience of managing albums consistent on all backends, then maybe your library could provide default images where required. A logo for your app, maybe. Users are unlikely to have empty albums for very long anyway.
I would go with
public boolean requiresDefaultImage;
or
public boolean requiresAlbumImage;
I would use something like allowsEmptyAlbum or emptyAlbumPermitted
That being said, adding an extra method means that the user of the class needs to know that this could even be an issue and remember to make the check before adding the album. This could be an issue because most developers "want to get things done fast" and would not know about the differences between services.
Even adding a note in the documentation is not enough because many folks calling "addAlbum" would never read the documentation of the method since it seems straightforward (see my research for details).
Ideally, you would either be able to create different factories for each service (and provide the information there), or, if you have to use a single API, find a way of gracefully failing or maybe adding a placeholder image.
I think you can make it even shorter by removing the redundant Album portion.
public boolean canBeEmpty();
public boolean requiresInitialPhoto ();
public boolean doesOnePhotoExist ();
public boolean needsOnePhoto ();
Create FlickerWebAlbum and PicasaWebAlbum classes. Each of them will represent behavior specific to each provider.
The short answer to your question:
boolean isDefaultPhotoRequired;
The longer answer: the default photo requirement isn't shared by all WebAlbums, so it's a perfect candidate for using inheritance. Move that behavior to a Flickr specific subclass. You could do something like add the creation of that defaultImage to a Flickr.init().