Lately I've read this comment on Reddit:
I think EventBus on android is popular because people don't know how to share a java object reference between android components like a Fragment and an Activity, or 2 Activities and so on. So basically I think people don't know how 2 Activites can observe the same object for data changes which I think comes from the fact that we still don't know how to architect our apps properly.
As far as I know:
directly reference values
((HostActivity)getActivity()).someValue
may cause problem such as memory leaks or NullPointerException
Callbacks or other observer pattern
EventBus,inner class like listener and etc
So I was curious that whether there is any other ways , could you share with me on it?
imo, there are few ways out of your opinion such as:
use local db, now ORM like Realm is really popular, its also safe way.
use share preferences if your object is able to convert to json, its up to your situation.
use intent with serialize/parcelable object bundle.
use a singleton, now #scope with Dagger 2 is good choice.
use RxJava as event bus.
Related
I have read many blogs about how singleton are vulnerable in android.so my question is how to maintain such global objects or list in application.i know shared preference is one way but is there any way to maintain such objects or list efficiently.any help will be more helpful.
You can use a file or SQLite database to save data in android app. You can check below links to learn more about saving data in a file or SQLite database:
Saving data to a file is ideal to store long sequences of data that are generally read in order
https://developer.android.com/training/basics/data-storage/files.html
Saving data to a database is ideal for repeating or structured data:
https://developer.android.com/training/basics/data-storage/databases.html
use sharedPreferences, Sqlite database to manage your objects, singletons are not very good, but static variables are more hard to maintain and will make testing the cide more tough, you can use Shared preferences to maintain a global state if the data is not very large, if there is large amount of data then use of sqlite is recommended.
Shared preferences are extremely easy to use, if you have problem using sqlite though you can use orm libraries for android
here's a link to one: http://greenrobot.org/greendao/
If you just want to keep a list as Global until your app is running, then create a new class let's say "Helper" and Initialize a Static List in that class. Now you can access that list anywhere within the app by "Helper.yourStaticListName" and you can also add/remove or get data from the list anywhere within the app.
But if you want to keep that list even when app has been closed, then there are two solutions for that.
First Create a local database "SQLite file" in your app and add/remove or get data from it.
Check this tutorial: http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
Second solution is to convert your data into a JSON and convert that JSON into String and save it in Shared Preferences. And whenever you need it just get the string from Shared Preferences and convert it into JSON and parse to get the data.
One last thing when you are talking about parsing a JSON, then "GSON library" is a good thing to work with.
Here is the link: http://guides.codepath.com/android/leveraging-the-gson-library
Hope this answer will help you.
How about using Android Service?
You can initialize / start it when your application started (and also stop them when your application stopped) and then bind them whenever you need (put and get your object / list).
I believe it will be an efficient way.
From conceptual point having a static variables or service-locators is very similar to having Singletons. Hence, having them as alternatives may not be be correct, if the intention is to avoid the Global state and consequences.
We can change Singleton-classes into instances, which are instantiated only once and injected into the components and methods as needed. We can use a IoC-framework to handle the injection part or do it manually with a factory pattern to construct (we can restrict only one instance creation as well) instances of the classes. This discussion thread gives lot of insights on the problem and various options.
So if I understand your question right, you need to store some global variables all over your application if that's so please take a look at this question
basically you create a class that extends application which would store anything you would like on start of your app and all of them can be accessed trough out the app.
hope this helps.
If you are trying to create a globally accessible object, the first thing you should ask yourself is: Why? Why do you need a globally accessible object? Most of the time you don't, and you can get away with creating an object with a limited scope which is passed around the app.
There are times when you do want globally accessible resources and using a singleton is just one way to accomplish that. According to the Android Docs your data storage options are:
Shared Preferences
Store private primitive data in key-value pairs.
Internal Storage
Store private data on the device memory.
External Storage
Store public data on the shared external storage.
SQLite Databases
Store structured data in a private database.
Network Connection
Store data on the web with your own network server.
Singletons are great, but the do have their own risks based on how they are implemented. Typically developers use this pattern when you are attempting to share a resource within the application, things like Loggers, Print spoolers, etc. There are multiple ways that you can create Singletons in Java, you can use a Lazy Initialization or Static initialization, each has their own pro/cons. In terms of "vulnerabilities", there are issues with whether or not the singleton is thread-safe, who/what can access it, and so on. This is why it makes sense to try and understand the problem you are trying to solve. Personally, I'm not clear on what exactly you are trying to solve, so I can't really elaborate on how this might help or hurt you. All I can say is that the biggest vulnerability is also it's greatest asset, which is that like most global variables, it can be accessed from anywhere at anytime. There can also be an issue whether or not the singleton is thread-safe.
Personally, I think you need to assess what it is you are trying to solve and the pick the appropriate solution. Maybe using a singleton is the correct solution, maybe it isn't. But understanding all your options and the strength/weakness of each one is going to be the best way to solve this issue. Unfortunately, you haven't provided enough context to your problem for me, or anyone for that matter, to give you a solid recommendation.
The best way to manage global objects is not having them at all. Based on my experience, in a lot of cases there are alternative options instead using singletons. There is so good explained in this post
shared preference is good but some time you will feel problem when do some modification make static constant variable in one pojo java class and use this variable anywhere.because shared preference will not change value after use or unless you dint modify .shared preference retrieving and storing is not very unfriendly. if you use constant you can modify easily .only one class you have to hit
Notify activity from service
I want to know if it is possible to do what the selected answer in the above post said, when your activity and service are in separate packages. Basically i have an object that is non-serializable (lets say a created view) and I want to send it from my service to my activity. Would be easy enough by using a custom binder, but as i've found out, you cant use custom binders when your service and activity are in separate packages.
I've been pondering this for a few weeks and it has really put a block in my project I am working on.
For those who will ask, I am trying to make a framework that allows "plugins" from other packages. But I am unsure how one would send non-serializable date back and forth between said service and activity.
It depends on the complexity of the object, If the object that you want to serialize is an object that comes from the Android SDK lets say a RelativeLayout or a Cursor I don't see that happening anyway, because those objects contains references to another objects that you don't have access to modify or make them implement the Serializable interface.
If your object is a class that you implemented and all references inside that class are also to another classes that you implementad (or to Serializable/Parceable objects) then sure you can. One way of doing so is, well, making them implement Serializable or making your own Parceable theres plenty of tools to achive this in a quick way like this or this one.
If no one of this answers satisfies you, then tell me what're you trying to send from the Service.
EDIT
Did you try to make a class implement both Serializable and OnClickListener and send it through the intent?
Sounds like you need some sort of Command pattern there.
I know similar questions have been asked multiple times. I think i read most of it. But none answer is applicable.
I need to pass complex Objects via Intents (Activity calls/Broadcasts). Everything is done within my process. That's why I see no reason to write my objects into Streams just to reassemble them a few milliseconds after. I want to pass my object reference through my application. Is there any way to do this.
Since my application will broadcast the same Event multiple times in a row I can't rely on static members. I need to get exacly the same object for what I broadcasted.
That's why I was thinking about a static "Referenceholder" that will accept an Object and return an integer that identifies this object in it's internal list so I can pass this integer via .putExtras. But as far as I know Java I could not clean up this Object from this list after it has been added because multiple Listeners could be interessted in the very same object and I would have to keep it in my Referenceholder for ever (assuming that a thread may be resumed at any time - even 2 minutes later).
Any ideas? Am I doing something wrong? Or any ideas of how I can clean up my referneces (probably after some seconds? this may lead to a crash but it seems to be more applicable than writing code that assembles and reassembles my objects for no reason)
Your options are pretty clear: There is no way to pass an un-marshallable object (Parcelable, Serializable) in an Intent. Full stop.
What you might be able to do is to pass something that is a reference to an un-marshallable object. The idea is that you would do something on the order of passing a key to a map that maps that key to the value that you are interested in passing. If both the Intent sender and the intent recipient have access to the map, you can communicate a reference to the un-marshallable object.
I don't understand, exactly, why you think static members are not what you want. I would guess that a static map, in a custom Application object, would be pretty much exactly what you want. ... and I suspect, from your comment about WeakHashMaps, that you've discovered exactly that.
... except that nothing you've said so far explains why you want to make your map Weak. Before you use a Weak map, have a look at Soft references, to make sure that that is not what you mean.
Best of luck
EDIT:
Forget about this solution. It does not work. Android is coping the Intent that you pass in .startActivity(). There is no way to get any reference inside a activity. This is - in my opinion - great bu****t my by google. You have to call your activity and place the referneces of your object in static members...
As metioned by G. Blake Meike, there is no way to pass Object references in Android via Intents. But you maybe can use WeakReferences.
A very excelent aticle about this topic is found here:
http://weblogs.java.net/blog/2006/05/04/understanding-weak-references
I got to that solution through this question:
Is it possible to get the object reference count?
So what I'm basically going to do is:
I will use Intents as a Key for a WeakHashMap and pass my Object as value. This seems to be the only Object that is suitable as Key since everything you put into the Intents extras will be serialized. Due to that, you can only pass one Object per Intent. You could implement Subclasses inside your Acitivity that can hold your Objects an put this Subclass into the map instead. But I'm still not sure if the Intent object that a receiver will get is the same that the caller created but I think so. If it is not, I will edit this solution (or maybe someone could clear that up).
It seems to me that passing extras via Intent calls is a violation of encapsulation, since classes are directly communicating with one another. That being said, the only viable alternative to this that I have found is setting a variable in some shared class and just having each activity pull data from it - part of me, however, can't help feeling that this isn't a great design choice either. Can someone shed some light on this?
Encapsulation, as one of the whale of Object-Oriented paradigm, assumes that you free programmers, who will use your class in future, from the necessity to know how does your component built inside and what complex aspects does it hold, carrying out this information to comfortable and clear programming interface (in the best cases).
Intent model was developed so, that it assumes interaction between main components of operating system, especially Activitys, and also it assumes that you need to accompany your intents with some concrete information such as kind of ACTIONs you want to perform, a CATEGORY of your intent and some set of DATA that need to implement your intents. So this is convenient model in such kind of interactions.
At the same time, using some shared class between activities when there is a ready solution for that, is rather irrelevant approach, IMO.
It isn't, you'll end up needing it. Usually I pass minimum info between activities and then check out big data in the launched activity's onCreate().
I am looking for some design patterns to use controlling a set of Activitys in an Android application. I am currently developing an app which I feel will go under many many revisions of the UI until its "final" release (if there ever is one). I was thinking something along the lines of an Observer pattern using a controller in the Service but I can't find any good examples. The only thing I find common references to is using AIDL for inter-process interface binding, which will not be applicable.
Basically what I want is for the Activity to implement a defined Interface such as showLoginScreen(), loginError() etc. such that ANY UI should be able to implement (the controller is not tied directly to the view, only its interface). If this is the cleanest way to accomplish this, what is the best accepted way of getting handles to active Activitys? I have always been confused what happens when you invoke a method on an Activity that is not active.
I was thinking something along the lines of a Map in the Application class serving as a singleton? The put() / remove() of the Map would be tied to onStart() and onPause(). This still doesn't guarantee the Activity is still alive though...a reference could be gained with a get() on the key, and then it could be paused() before the Service has a chance to call its interface.
Any suggestions or insight would be appreciated.
edit: I have looked at other posts such as MVC pattern on Android however they mostly don't address implementation (and that accepted answer I just flat out disagree with anyways)
To use an observer/observable pattern between your activities and your service, you will need to use Bound services.
This way, you can get a handle to the IBinder which can act as your Observable and you do not have to worry about AIDL. You can ensure that the Service has been bound to in the onServiceConnected() method in your ServiceConnection. Keep in mind that your service will only be alive as long as there is an Activity bound to it, otherwise it will be stopped.
I would recommend reading the android Bound Services documentation as it explains the usage very well.