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));
}
}
Related
In Android, how do I take an action whenever a variable changes?
So I want to implement a listener for an object I created. What I want it to do is execute a block of code when its value changes from false to true.
As I am following this thread, I can't understand where the person wants us to implement the last block of code containing the logic for the listener.
Could someone, hopefully, guide me in the right direction?
(This question is being asked here as I don't have enough rep. points)
That last bit of example code triggers the listener, so it basically needs to be run whenever the "event" occurs. In this case the "event" is whenever (wherever in the code) the value of the variable changes.
If you have a setter and that is the only place the value changes, that is where you'd put it. If you are changing the value in multiple places throughout your code, I would make a new private method (call it signalChanged), put your code there, and then call it immediately after the variable assignment in the cases you want the listener to fire.
Here's an example (some code borrowed from linked answer, haven't checked that it compiles).
public class MyObj
{
public MyObj(int value)
{
setValue(value);
}
private int myValue;
public int getValue() { return myValue; }
public void setValue( int value )
{
if (value != myValue)
{
myValue = value;
signalChanged();
}
}
public interface VariableChangeListener
{
public void onVariableChanged(Object... variableThatHasChanged);
}
private VariableChangeListener variableChangeListener;
public void setVariableChangeListener(VariableChangeListener variableChangeListener)
{
this.variableChangeListener = variableChangeListener;
}
private void signalChanged()
{
if (variableChangeListener != null)
variableChangeListener.onVariableChanged(myValue);
}
}
you have to create a callback interface
here is a good about custom listener tutorial
here is a sample
public class MyObj {
VariableChanger onVariableChanged ;
public void setOnVariableChanged(VariableChanger onVariableChanged) {
this.onVariableChanged = onVariableChanged;
}
void log(){
boolean changed = false;
onVariableChanged.onVariableChanged();
//this will call it
}
interface VariableChanger{
void onVariableChanged();
}
}
class logic {
MyObj mo = new MyObj();
void main(){
mo.setOnVariableChanged(new MyObj.VariableChanger() {
#Override
public void onVariableChanged() {
//do your action
}
});
}
}
In Android, like any language, most developper uses logic comparisons to check values (if, else, switch, =, !=, >, <, etc) or Event (signal)
What kind of listener do you want to implement?
I hope that we can pass data between android application components
by following ways.
1.we can pass data using intent object,
2.we can implement serializable , parcelable interface and pass objects by using intent,
3.we can create a new class by extending Application class, to access global members from anywhere
the android application,
4.sharedpreference ,
5.sqlite.
Are there any other mechanism to send data between android application components?
Another option is create ApplicationPool.
Follow the below steps:-
Initiate the ApplicationPool :-
ApplicationPool pool = ApplicationPool.getInstance();
modify the data on details page and add to pool
pool.put("key", object);
get the modified data on list page from pool
Object object = (Object) pool.get("key");
important notes:- notify the listview or gridview after getting the data
ApplicationPool class file
public class ApplicationPool {
private static ApplicationPool instance;
private HashMap<String, Object> pool;
private ApplicationPool() {
pool = new HashMap<String, Object>();
}
public static ApplicationPool getInstance() {
if (instance == null) {
instance = new ApplicationPool();
}
return instance;
}
public void clearCollectionPool() {
pool.clear();
}
public void put(String key, Object value) {
pool.put(key, value);
}
public Object get(String key) {
return pool.get(key);
}
public void removeObject(String key) {
if ((pool.get(key)) != null)
pool.remove(key);
}
}
Another way is to use static elements, wether it be:
Static fields (with public access for example)
Static properties (meaning private fields with getter and/or setter)
Singletons
Possibly nested classes
While the use of static variables in OOP is debatable, they introduce global state and therefore are a way to accomplish sharing of data inbetween activities too.
1) HashMap of WeakReferences, for example:
public class DataHolder {
Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();
void save(String id, Object object) {
data.put(id, new WeakReference<Object>(object));
}
Object retrieve(String id) {
WeakReference<Object> objectWeakReference = data.get(id);
return objectWeakReference.get();
}
}
Before launching the activity:
DataHolder.getInstance().save(someId, someObject);
From the launched activity:
DataHolder.getInstance().retrieve(someId);
2) Or strange method: store data on server O_o
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;
I have an app that uses custom Exceptions, such as this:
public class SomeException extends Exception{
private int iCode;
private String iMessage;
public SomeException(){
iCode = 201;
iMessage = **//Get the localized string R.string.error_201??**
}
#Override
public String getMessage() {
return iMessage;
}
#Override
public int getCode() {
return iCode;
}
}
Obviously, I want lo localize the error message. I have possible solutions but non of them satisfy me.
1) Pass "Context" to the constructor, and do ctx.getString(R.string.error_201)
--> Fail, as this Exceptions are sometimes thrown from MODEL classes, so they don't have a Context
2) Pass "Context" when retriveing the message in getMessage() function,
--> Fail, It's necesary to override the super method, to work as all other Exceptions.
Solution I have now: All activities in my app have this onCreate:
public void onCreate(...){
Utils.RESOURCES = getResources();
...
}
Very dirty code... I don't like the solution. My question is then,: is there a way to access the resources without the Context? And most important, How would an application such as mine solve this problem?
What about
public class MyException extends Exception {
private int iCode;
public MyException(int code) {
this.iCode = code;
}
#Override
public String getMessage() {
return "MyException code " + String.valueOf(iCode);
}
public String getLocalizedMessage(Context ctx) {
String message;
if (iCode == 201)
message = ctx.getString(R.string.error_201);
else if (iCode == 202)
message = ctx.getString(R.string.error_202);
// ...
}
}
Even if there was way to access context in different way, you should not do it. If you need to emit exceptions where you cannot pass Context, you should be able to access context before you display such error. I cannot see reason why you should create localized error messages from constructor. You can log to logcat not localized versions if you need. And where you want to display something in UI, you should have context at hand.
You can access only system wide resources without Context.
You need a Context, so I would suggest You to get it as soon as possible, and make it available through a static method or variable. You do the same thing in every Activity, but there is a cleaner method. You should make a custom Application, and override its onCreate() to make the resources public:
public class App extends Application {
private static Resources myResources;
#Override
public void onCreate() {
myResources = getBaseContext().getResources();
super.onCreate();
}
public static Resources getMyResources(){
return myResources;
}
}
The other thing you have to do is to set the Application in your manifest:
<application
android:name="{your_package}.App"
...
Now you can access the resources in all of your Activity without any preparation. Your custom Exception class could also use the externalized resources.
I've got a class which contains a getter and setter for the variable "artist":
Class:
public void setArtist(String artist) {
this.artist = artist;
}
public String getArtist() {
return artist;
}
I'd like to call setArtist from an activity like so:
Activity 1:
Playlist.setArtist(someString)
But eclipse tells me I need to change setArtist to static. The whole point of me using setters was to avoid having any static references. Am I doing something wrong, or is there another way to accomplish this?
It entirely depends on where and when you want your object. You could do something like this:
class Artist implements Serializable{
public static final String EXTRA = "com.your.package.ARTIST_EXTRA";
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Activity 1:
public void onCreate(Bundle savedInstance){
// ....
Artist artist = new Artist();
artist.setName("Rolf");
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra(Artist.EXTRA, artist);
startActivity(intent);
}
Activity 2:
You then have a reference to your Artist in the second Activity:
public void onCreate(Bundle savedInstance){
// ....
Artist artist = (Artist) getIntent().getSerializableExtra(Artist.EXTRA);
Log.d("YourApp", "I have the artist! "+ artist.getName());
}
Watch what you are serialising as you cannot serialize certain objects.
Another way to go it would be to have a class that extends Application and keep a reference in there, then you could retrieve it from any Activity context.
You cannot assume that the other activity will be in memory so its the wrong way to do it. I would read some of the android activities and how to use them.
http://developer.android.com/guide/topics/fundamentals/activities.html
please make an Object of Playlist then set the variable.
Playlist mObjPlaylist= new Playlist();
mObjPlaylist.setArtist(someString);
If you want to access a method like A.show(), the show() method should be a static method, coz static method does not require objects to be accessible.
One solution is to make these getters and setters as static method and access it as you are accessing it now.
Another solution, is to use, Singleton pattern, so in this case you don't need to make these methods static, you just need to get the singleton object of that class and access these methods like this:
PlayList.getInstance().setArtist();
The way you are dealing with activity is not the right way.
If you need some common data to use in both Activity then you can manipulate it by using a common Class,not putting it in Activity.Also if you want to pass some data while launching another activity from an activity you can pass it through intent extra.
class PlayList{
private static PlayList self=null;
private string artist;
public static PlayList getInstance(){
if(self==null){
self=new PlayList();
}
return self;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getArtist() {
return artist;
}
}