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.
Related
I'm very new to java and want to ask for a help about design. I'm going to build a simple survey app for android in java.
Here is how I see the app:
The main page (activity_main) contain LineEdit for ID and two buttons: Login and SignUp. This activity onCreate loads all registered users and questions from DB.
Sign up page (activity_signup) contains several LineEdit fields for user info as well as SignUp button. Also it provides free ID onCreate.
Profile page (activity_profile) contains some user info (as TextView), possibly and a Survey button.
Survey page (activity_survey) contains Question, Answers and two buttons: Prev and Next.
Please mention if something might be improved.
Questions:
Should I store all users and questions as private field in class MainActivity or somewhere else? (Assume that DB is so small that it perfectly fits in RAM)
How can I modify the DB with newly created user from activity_signup? It is rather general question, like how can I access private fields from other activities preserving encapsulation?
I'd like to have a filed like private static User current_user in class ProfileActivity. But I can get the user only from DB, which is private field of class MainActivity. How can I pass the user from activity_main to activity_profile (again preserving encapsulation)?
activity_survey contain answers of different types, e.g. Yes/No; single/multiple choice (+ your variant) etc. How can I handle this in java? My idea is to create an abstract class AbstractQuestion with method fillLayout and inherit several class ConcreteQuestion (here concrete should be replace with an appropriate title) from it which contains implementation of certain type of question. Store all questions in array of AbstracQuestion's. Is it doable in java or is there more right way to do this?
Thanks in advance for any help!
Don't store such objects in Activity. You have several options for data persistence - these are listed here https://developer.android.com/training/basics/data-storage/index.html - of course that does not cover any "external" sources such as databases like Realm or Firebase but let's keep to the basics.
If your data is complex and you think that it would be easy for you to retrieve it using SQLite queries then the SQLite Database is the way to go. You can access it using ContentProvider which can be queried from any place where you have Context.
You can also store it locally on your internal or external storage with simple Serializable classes. Imagine a single object let's call it Database that is Serializable and that contains all the data you need. You could load it in your App startup (like in extended Application class) and store the reference so it won't get garbage collected. Then you can access it from a Application static method you could write to get the reference. It is probably the fastest way to implement a simple storage with fairly complex structure but that is probably not the best if your data is "big". It will increase your App start time (preferably make the load and save operations asynchronous).
If your data is simple you can use SharedPreferences to store "key-value" data. This is a little like second approach but using the Android framework to do it.
The option 2 and 3 require that your data is Serializable or Parcelable. As Android says that Parcelable should not be used for persistence but rather for communication let's skip that one.
You can either make you objects Serializable or translate them to json objects with i.e. Gson library. and store those serialized json objects. Making them serializable directly may be faster approach but sometimes keeping jsons makes more sense.
You can't and you shouldn't have to.
If you wan't to keep your data in static fields move them to extended Application class (make sure you point it in AndroidManifest.xml with specific xml parameter) and access it from there. You can get access to your Application class whenever you have Context via context.getApplicationContext() that you can cast to your custom class.
To tell Android to use your custom Application class use the following in AndroidManifest.xml:
<application
android:name=".YourAppClass"
...>
...
</application>
I am not sure if I get the 4th question right. Basically if you have multiple values you need to store your results in some collection i.e. ArrayList. Your whole questionare could be represented by a Map<Question,List<Answer>> then <- arbitrary class names (these could be enums too)
So what I'm wanting to do is have a few different single manager classes that handle the caching of data that I've pulled down from the internet. I want the data in these classes/objects to be accessible from different activities in my application, whereby any of the activities can manipulate data or call functions as needed.
Eg, I have a UserDatabasemanager where I will store the initial raw JSON data I pull down from the internet and an array of User objects which is a distilled version of that JSON data.
My app at various times will pull data down from the web and will update the User array as data changes. Eg, initially pull down a list of users that fit a criteria. So I then cache all the usernames and IDs into the User objects. Should the application then focus in on a particular user page, it will then download that user's description text and store the new description into User object. (All of which I think I cant do currently with my knowledge of programming)
I've been reading up on sending objects via Intents with Parcelable and Serializable which seems a bit of a round about way of doing things for shared data between Activities.
How to send an object from one Android Activity to another using Intents?
Passing data through intent using Serializable
Since my intention is to use these classes/managers/objects (whatever we want to call them) as single instances I'm not too fussed about following encapsulation to the letter as their job is to provide and update my cache data based on the needs of the Activities.
I'm still very green with all this Android/Java stuff, but it seems this sort of thing would be fairly straight forward in C/C++ with pointers. It seems that even if I was programming directly with Java I could pass around references to objects fairly easily, but the structure of Activities seem to be in such a way that it doesn't lend itself to easy passing data around in my own program?
One easy (but not great) way to achieve this is to use the Android Application class to store (the singleton) instances of your managers. You can always retrieve a reference to your application by calling getApplication() on any activity.
You need to provide your own implementation of the Application class so that you create the managers in the onCreate() method. You should also create strongly typed getters for your managers.
Also, consider what you need to do for the system callbacks the Application may receive such as onLowMemory().
So what I ended up doing in the end is making a Globals.java file with the following contents
public class Globals {
public static ArrayList<User> userObjArray = new ArrayList<User>();
//Weird magic class stuff
private static Globals instance;
private Globals() {
}
public static synchronized Globals getInstance() {
if (instance == null) {
instance = new Globals();
}
return instance;
}
Then whenever I wanted to use data from the Globals I would do something like...
Globals.getInstance().userObjArray
This seems to be working exactly how I want it to. Its not great for encapsulation, but that wasn't the goal for what I needed to get done.
I think you should use android service and create binders in your activities.
http://developer.android.com/guide/components/services.html
Can anybody please tell why we need to serializable object for passing one activity to another activity in android? Android is following Java syntax. In java we can pass object to another class without serializable.
Thanks
In ordinary java programs passing parameters(Object type), is kind of create a new handler to the object and giving to another method (In regular words passing the reference by value).
But when it comes in android, passing object references from activity to activity, where their states have to be persisted, is a serious headache.
One way you can do is create a static object in the first activity and access from the second, though this seems to be a easiest way, there is no guarantee that the system maintains the activity in the memory. Therefore the second activity may loose the object reference.
Other way, and the mostly recommended way is serializing(Kind of flatten the object) the object and pass with the intent as extra. In android there are two ways to serialize.
Implement the java's serializable interface
Implement the android's parcelable interface
However, on the android, there is a serious performance hit that comes with using serializable, the solution is using parcelable.
You can find a pretty good tutorial and explanation on android parcelable implementation here.
We need to understand following concepts before getting to the answer:
Android uses Binder for inter-process process. It is required even for simple app because the OS and the apps run in different processes.
Marshalling:
A procedure for converting higher level application data structures into parcels for purpose of embedding into Binder transaction
Unmarshalling
A procedure for reconstructing higher-level application data-structures from parcels received though binder transactions.
You can consider Intents as higher level abstraction of Binder
Based on the documentation following is the way how intent communication occurs:
Activity A creates an Intent with an action description and passes
it to startActivity().
The Android System searches all apps for an intent filter that
matches the intent. When a match is found,
the system starts the matching activity (Activity B) by invoking
its onCreate() method and passing it the Intent.
Why Parcelable or Serializable
IPC (Inter Process Communication) requires data in Intent to be Marshalled and unMarshalled. Binder provides built-in support for marshalling many common data-types. However when we define custom object, it would impact this process and the final object received might be corrupted during the process.
When you define custom object, you need to be responsible for providing this marshalling and unmarshalling which is achieved through Parcelable and Serializable (Since comparison between these two would be another topic I won't discuss much here). Both of these provide mechanisms to perform marshalling and unmarshalling. This is the reason why you need to use Parcelable or Serializable.
Using Parcelable you write the custom code for marshalling and unmarshalling the object thereby you gain complete control over the process.
Serializable is a marker interface, which implies the user cannot marshall the data according to their requirements and its done on JVM, which doesn't give any control at your side.
Disclaimer: Description above is my understanding for the rationale behind the need for serialization based on some
documentation
There are basically two questions in your question, so let's decouple it.
Why marshall in a Parcelable instead of passing an object reference directly?
It's obvious faster and more memory efficient to reference objects rather than marshall/unmarshall them. So you shouldn't use Parcelable when you can pass the object directly.
However, there are situations where you may not have access to the object reference.
in Intent because the process that handles the Intent may not be the process that emitted the Intent (it's an inter-process communication)
in Activity lifecycle, for instance in onRestoreState(), because the whole app may have been killed by memkiller when the user wants to resume it.
everywhere else where Android frameworks requires
In IPC, why use Parcelable rather than Serializable like Java does?
That's only a performance optimization.
If We want to pass object from Activity to to Another Activity . We need to save the passing state.
//to pass :
intent.putExtra("MyClass", obj);
// to retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");
This is a bit of a general question, but I will give a specific example for you.
I have a bunch of activities in an App. In all of the activities, there is a Facebook button. When you click the button it takes you to a specific Facebook page. I wish for the button to behave exactly the same way on every page.
Right now, in every single Activity, I create an onClickListener() for the Facebook button and make the intent and start the activity. It's the same code in every single Activity.
What is the best way to write this code once and include it in multiple activities? Is there anyway to include other .java files?
One solution that I know would work, is to make a base CustomActivity class that extends Activity and then have all activities extend CustomActivity. Then put my onClickListener() code in CustomActivity. I'm new to Java though and I wasn't sure if that was the best approach or not. Some of my Activities already extend other custom activity classes as is, so extending things that extend more things might get kinda messy, I dunno.
UPDATE
Playing the devil's advocate here: Lets say I went with the inheritance route and I create some CustomActivity that I want my Activities to extend. CustomActivity would contain a bunch of general code that I need to use for all Activities, including but not limited to the Facebook button functionality. What happens when there is an Activity that I need to use generic code from the CustomActivity but there is no Facebook button in that specific Activity?
A common base class is perhaps the best approach. (It doesn't work quite so well if some of your activities extend Activity and some extend Activity subclasses (such as ListActivity).
An alternate approach is to create a separate class that implements the logic of your click listener. This doesn't eliminate all duplicate code — each activity still needs to instantiate and register a listener — but the logic for what to do will only need to be written once in the listener class.
In either alternative, you might consider assigning the android:onClick attribute to the button. That way you don't need to register a click listener; you just need to implement the target method in each activity. This is particularly useful with the base class approach.
UPDATE
Suppose you go the inheritance route and you want an activity with no Facebook button. If you are using the android:onClick technique, then you don't have to do anything different in your code — since no button will invoke your onClick method, the method will just sit there doing nothing. If you are installing an OnClickListener in code, then you just need to test that the button exists (i.e., that findViewById() did not return null) before registering the listener.
Generally a common base class is NOT the best approach (although it's certainly valid).
This took me (and every OO programmer who "gets" OO that I know of) a while to really grok, but you should use inheritance as sparingly as you possibly can. Every time you do it you should ask yourself if there is REALLY no other way to do this.
One way to find out is to be very strict with the "is-a" test--if you call your base activity a "Facebook Activity", could you really say that each child "is" a Facebook activity? Probably not. Also if you decided to add in Twitter to some of the pages (but not others), how do you do this?
Not that inheritance is completely out! A great solution might be to extend a control to launch your facebook activity and call it a facebook button--have it encapsulate all the stuff you need to do to connect to facebook. Now you can add this to any page you want by simply dragging it on (I'm pretty sure android tools let you add new components to the pallet). It's not "Free" like extending your activity class, but in the long run it will cost you a lot less stress.
You probably won't believe me now, we all need to learn from our own experience, just keep this in mind and use it to evaluate your code as you evolve it over time.
--edit, comment response--
You can encapsulate any facebook activity you think you will use a lot in it's own class--get it to a bare minimum so you can just add it to any class in a one-liner.
At some point, however, you may decide that it's STILL too much boilerplate, I totally understand. At that point you COULD use an abstract base activity like you suggest, but I wouldn't hard-code it to handle facebook explicitly, instead I'd have it support behaviors such as facebook (and maybe others), and turn-on these behaviors as desired. You could then tell it NOT to add the facebook behavior to a given screen if you like, or add in Twitter to some of them.
You can make this boilerplate minimum, for instance if you want "Standard" functionality, you shouldn't have to do anything special, if you wish to disable facebook you might start your constructor with:
super(DISABLE_FACEBOOK_BEHAVIOR);
and if you want one that also enables Twitter you could use:
super(DISABLE_FACEBOOK_BEHAVIOR, ENABLE_TWITTER_BEHAVIOR);
with a constructor like AbstractAction(BehaviorEnum... behaviors).
This is more flexible and you actually can say that each if your activities IS-A "behavior supporting activity" with a clear conscience.
It is, of course, a perfectly good approach to be less flexible at first and refactor into a pattern like this later when you need to, just be on the look-out for your inheritance model causing problems so you don't let it mess you up for too long before you fix it.
Well, extending things is the principle of OOP, so I don't think this is a problem to have more than one level of subclasses. The solution you thought about is in my opinion the best.
Absolutely. Use inheritance to gain some reusability as you should with OOP. You'll find, as you progress, that there are gonna be more and more things you'd like to reuse in your activities -- things more complex than an onClickListener for a FB button -- so it's a great idea to start building a nice, reusable "super" activity that you can inherit from.
I have a simple Android application that uses an instance of a class, let's call it DataManager, to manage access to the domain classes in a Façade-like way. I initially designed it as a singleton which could be retrieved using static methods but I eventually got irritated with the messiness of my implementation and refactored to what I reckoned was a simpler and cleaner idea.
Now the idea is that for each file that is opened, one DataManager is created, which they handles both file I/O and modification of the domain classes (e.g. Book). When starting a new Activity, I pass this one instance as a Serializable extra (I haven't got on to using Parcelable yet, but expect I will when I have the basic concept working), and then I grab the DataManager from the Intent in the onCreate() method of the new Activity.
Yet comparison of the objects indicates that the object sent from one activity is not identical (different references) to the object retrieved from the Bundle in the second Activity. Reading up on Bundle (on StackOverflow, etc.) suggests that Bundles cannot do anything other than pass-by-value.
So what is likely to be the cleanest and safest strategy for passing an object between Activities? As I see it I could
Forget about passing by reference and live with each Activity having its own DataManager object. Pass back the new DataManager every time I close an activity so that the underlying activity can use it. (The simple solution, I think.)
Go back to using a singleton DataManager and use a static method to get it from each Activity. (Not keen on using singletons again.)
Extend Application to create a sort of global reference to DataManager. (Again, not keen on the idea of globals.)
Is that a fair summary? Is there some other healthy strategy I could use?
Another approach would be to create a service. The first activity would start the service and bind to it, when you launch a new intent, unbind the first activity and when second activity starts, bind to the service.
This way you don't have to ever stop the service or worry about passing data between activities.
Java does not have pass by reference so that option is out, I would suggest dependency injection for passing data between the activities. Otherwise definetely the singleton would be the way to go.
The prescribed one is Going by implementing Parcellable interface, thats the way to pass Objects between Activities.. and the 2nd and better choice is to make a Singleton to be sure its single Object.
Create your DataManager as a Singleton that implements Service. Bind the service to your application in the manifest xml (see the link), and you will have a persistent singleton your activities can access without issues.
Passing parcellable arguments can quickly get very messy if you need to get a lot of data. The singleton approach, although usually considered an anti-pattern, works like a charm in cases like these. Just remember to not create multiple singletons that interact with one another.
I would suggest using an Application Subclass. It allows you to hold a single reference to the DataManger class and is persistent as long as your app lives.
A singleton with a static field will also work, but there are some place in the documentation where it says that the content of static fields is not a safe place to store your data. As I understand static fields should persist as long as your ClassLoader stays in memory. Therefore a singleton should only vanish if the whole process leaves the memory and in that case the application class will also leave the memory, but it will call the onDestroy methods of the Application and that enables you to safely close your DataManager and persist important data to memory.
That said to your two variations.
The Android way to go would be to make your DataManager a ContentProvider. This will make it possible to access your Data from every Activity without holding a global reference. I'm not sure how you would build a caching Content Provider that stays in memory and is not reinstantiated too often.