is it expensive to always pass Activity as an argument to a method?
You see, I have this class (this is where I put the commonly used methods by my activities). And all my methods there have Activity as a parameter, because the results of those methods will need to be send back to the activity that invoked the method, so basically I need to know to whom should I throw back the results, so I always have like:
public static void processThis(Activity activity){
// some Code
}
I just like to know if this is against the best practices or if this is expensive to use?
Thanks. Looking forward for your explanations that will enlighten me.
Added:
I'm extracting commonly used methods from my activities to promote code reuse. Like, ActivityA use methodA and send broadcast back to ActivityA, same way goes for ActivityB which uses methodB(same as methodA) and send broadcast back to ActivityB. So what I want to achieve is to to extract that methodA and methodB which basically are the same, and put them into another class, and add a parameter Activity so I can know to whom do I need to send the broadcast back. Thanks.
In Java, all parameters that are not primitives are implicit pointers; consequently, passing an object such as activity only requires passing around the address at which the Activity is located in memory, so passing such a thing is not an expensive thing to do in Java.
So, the real question you should ask yourself is not whether it is expensive, but rather if it makes the most sense (from a logical / maintainability perspective). If it makes sense, then by all means do it.
Related
There are 3 activities: A->B->C. Each contains a Button (to open next activity) and a EditText.
For example: if I type some text in C and go back to A(by pressing Back Button), how can I see the same text there?
I know 3 solution:
LocalBroadcastManager
SharedPreferences
Create Singleton class with static field and then get this field in onStart method of A - which cons of this solution?
IMHO, there are always cons in using Singleton design pattern in your applications. Some of them are (from the top of my head):
Coupling between otherwise unrelated objects and flows through Singleton's instance
Emergence of a "global state", which makes debug a lot harder
Inability to mock static fields and methods through "conventional" mocking
The fact that a reference to Singleton can be easily obtained in any part of the application leads to a total mess (people stop thinking about dependency graph)
Singletons tend to breed: you introduce one, then another one, then you find yourself with 10 singletons which hold app's state in a "global cloud state"
Note that what you're trying to do is against Android guidelines - if the user taps on "back" button, then he should find the previous Activity or Fragment in the exact same state it had the last time the user saw it, without any additions (unless you explicitly don't want to save it in the back-stack).
If you still want to do it, then I could suggest several options:
Use SharedPreferences and store the value there. Get the value in each Activity and diplay it in onResume()
Use startActivityForResult() call in order to start new Activities and pass the value back in the result. Note that by default press on "back" cancels the action, therefore you'll have to override onBackPressed() method.
Override onBackPressed() method in Activity in such a way that it starts another Activity (instead of just popping the back-stack) and pass the value in the Intent that you use. You might want to use FLAG_ACTIVITY_CLEAR_TOP in this case.
Use some event bus that supports "sticky" events. When user inputs the text you post a sticky event to event bus. In onResume() of Activity you check whether event of this type exists and if it is - you update UI.
Once again - the fact that you CAN do what you want doesn't mean it SHOULD be done.
Simply set into onResume() method of your class A, a call to the Singleton class instance you want to save (or istance of Application class which is the same)
LocalBroadcastManager is not a reliable option. It assumes the bottom activity to still be alive, which might not be the case. While you use B, A might be collected to free resources. Also, you should unregister LocalBroadcastManager receivers onResume(). So, no.
Singletons with static fields are generally to be avoided. It’s not worrying for a single string of text, but singleton fields are easily forgotten and can lead to memory leaks. Better to avoid this pattern if possible, and in your case it is.
Possible options.
If the field is something that must persist, e.g. user editing his username, use SharedPreferences or another storing solution (saving to a server, saving to cache, saving to device SQLite database).
If the field is temporary and is the result of activity B, you can start activity B with startActivityForResult() and then send the result back to activity A through an Intent.
For your problem the simpliest solution - store your value in Application class. Any activity can access it and read/write values.
Cons is that if you accidentally store static reference to activity, it will cause memory leak.
You may try using EventBus for horizontal communication: Activity-> Service, Service -> Fragment, etc.
It has static instance by default plus you can subscribe/unsubscribe to it in onPause and onResume methods.
Another advantage is a STICKY EVENTS - you can post event from Service and it will wait until something handle it - Activity will receive this event when it is ready - after onResume().
Since the child activity is created by calling the startActivity(intent) from the Parent Activity, it is guaranteed that the parent object exists while the child activity is running.
From that point of view, can I just manipulate the Parent's public variables at the child's class instead of calling startActivityForResult() after I come back?
Why do we need to use the method?
it is guaranteed that the parent object exists while the child activity is running.
No, it isn't. For starters, startActivityForResult() can be used across process boundaries, where the activity you are starting is in another app. The activity that is started cannot access the activity that started it, as they are in separate processes. Beyond that, it is possible that the process where the original activity resides will be terminated while it is in the background, as the user is in the second activity — this happens a fair bit when the second activity is a camera app, launched in response to something like an ACTION_IMAGE_CAPTURE Intent.
can I just manipulate the Parent's public variables
One activity has no access to another activity instance. The only way that would be possible is via static references to activities, which are tricky to get right without introducing memory leaks. And, again, that would only work where both activities are in the same process.
Why do we need to use the method?
You don't. There are any number of ways of writing UIs on Android. Few require the use of startActivityForResult(). For example, if these two bits of UI are that closely coupled, perhaps they should be in a single activity, where the bits of UI are separate fragments.
Suppose I have an activity MyMainActivity, let's say complex enough with a bunch of code.
From another activity, to access a public variable or a method I instanciate :
MyMainActivity ma = new MyMainActivity();
ma.editVariableMethod();
String example_variable = ma.public_examplevariable;
When I instanciate MyMainActivity ma, is it like creating the hole activity again and storing everything from MyMainActivity to memory, and that way it takes the same amount of memory it would take if I was starting MyMainActivity, or is it just a link which permits to edit variables from MyMainActivity?
You can't instantiate an Activity. The framework has to take care of it. If you want to use public methods either make them static OR get a reference to a valid instance of the activity object.
Edit:
As Squonk pointed out, depending on your use case, it might be a better idea to just extract the shared logic to another new class, at least until you know what you're doing. Giving "full access" to internal variables or even methods in an Activity might seem to work, but it's very likely NOT the right approach.
It is a bad practice to share memory-resident objects between objects in Android, no matter what the objects are. Android won't ensure that it will work. There are alternatives available for most use cases. In the particular case of "accessing a public variable" in another Activity, you can call startActivityForResult(), or ensure that your Activities store data they want to "share" in SharedPreferences, etc.
If you have two or more Activities that use the same method, you should first consider if the class needs to be abstracted into a separate object. Ideally, Activities should be frameworks that delegate to POJOs.
My launch activity starts up another activity whose launch is set to single instance. In this 2nd activity, I have a public method. I then start up a 3rd activity and that activity needs to access the public method in the 2nd activity. I don't want to use startActivity and pass it extras because I assume the onCreate will get called (or am I wrong?) and I need to avoid the 2nd activity from reinitializing itself.
When an activity is started using startActivity, is it possible to gain access to the underlying class instance itself and simply call the method?
I actually came up with a simple solution. As a matter of fact you can access the underlying class of an activity. First, you create a class that is used to hold a public static reference to activity 2. When activity 2 is created, in its onCreate method you store "this" in the static reference. Activity 2 implements an interface with the methods that you want available to any other activity or object. The static reference you hold would be of a data type of this interface. When another activity wants to call a method in this activity, it simply accesses the public static reference and calls the method. This is no hack but is intrinsic to how Java operates and is totally legitimate.
It is not a good idea.
As I can understand method from second activity is actually not connected to particular activity while you want to call it from another one. So carry the method out to other (non-activity) class (maybe static method) and use it from both activities.
It's not directly possible to gain access to activity object started using startActivity (without using some hacks). And frankly you shouldn't even trying to accomplish this.
One Activity component can cycle through several Activity java object while its alive. For example, when user rotates the screen, old object is discarded and new activity object is created. But this is still one Activity component.
From my experience, when you need to do things you described, there is something wrong with your architecture. You either should move part of activity's responsibilities to Service or to ContentProvider, or use Intents, etc. Its hard to recommend anything more specific without knowing more details.
No there is no way to pass a reference via startActivity() however you can use some sort of shared memory to keep reference to your Activity. This is probably a bad design. However passing an extra with your Intent will not cause onCreate, that is completely related to the lifecycle.
This is a pretty simple question, but I have been unable to find anyway to accomplish what I am trying to do...
I want to launch a new Activity to display some complex information. Because of the complexity, it is undesirable to serialize the information into the intent's parameters. Is it possible for the the new Activity to get a reference to the launching activity, so it can call its methods?
If you use a custom application class, you can store information that will be kept between the activities.
See a tutorial here for instance.
The lifetime of an Activity cannot be depended upon. In this case, one way of sharing data is to have a singleton which holds the data to be shared between the two activities.
You can add a public static field to the first activity containing this (the first activity).
But beware that the first activity could be destroyed by Android while you are using the second activity, so you will have to implement a fallback method if the first activity is destroyed.
And don’t forget to unset the public static variable in the onDestroy() callback of the first activity or you will leak memory.
Is it possible for the the new Activity to get a reference to the launching activity, so it can call its methods?
Please do not do that. Android can and will destroy activities to free up memory.
Complex information like you describe should not be owned by an activity. It should be held in a central data model, like you would in any other application. Whether that central data model is mediated by a Service or a singleton or a custom Application object depends a bit on the type of data, caching models, risks of memory leaks, and so on.
You can make your complex objects public and static in ActivityA, and access them in ActivityB like this:
MyCustomObjectType complexFromA = ActivityA.complexObject;
this will work, however while in ActivityB, you can't always be sure that static objects from ActivityA will exist(they may be null) since Android may terminate your application.
so then maybe add some null checking:
if(null == ActivityA.complexObject) {
//go back to ActivityA, or do something else since the object isn't there
}
else {
//business as usual, access the object
MyCustomObjectType complexFromA = ActivityA.complexObject;
}
You could also use a Singleton object which extends Application. You would have the same problem when Android terminates your application. always need to check if the object actually exists. Using the Singleton extending Application approach seems to be the more organized way - but adds more complexity to implementation. just depends what you need to do and whatever works for your implementation.
You should create a separate class that both the activities can use.
public class HelperClass{
public void sharedFunction(){
//implement function here
}
}
I would recommend staying away from static variable in android. It can cause some unexpected behavior.
Use getParent() from new activity and call parent's method
Android Activity call another Activity method