I would like to determine if this is bad practice, since I have implemented this in some locations.
I have two activities, MainActivity and SecondActivity.
If I want to transfer the string "Hello" from Main to Second, I use a class called Transfer. In this class I have a static String that I set to "Hello", which I access from the onResume method of SecondActivity.
How does android manage the "Transfer" class? Is it tied to MainActivity and destroyed along with it? Is there any other behavior I should be aware of?
Given that the String field is static, I'd say is bounded to the whole process and not to the MainActivity.
The problem is, the android os might free your app's resources to start another process.
What may happen is that your app gets backgrounded, the os needs it resources and frees the memory, and then the user gets back to SecondActivity. The process gets recreated and the previously initialized static field is now null.
If your need is to pass Strings between activities, I would bundle them into the intent's extras.
Static members exist as long as the app is in the memory.
This approach works fine. Another way to share data between two activities is to make use of putExtra to put data into second activity and getExtras to get the data.
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().
I'm writing a simple android application which is basically a modification of the fragments demo available in the android documentation.
In the app, there is a file called Ipsum.java which has a static ArrayList of Strings called Headlines.
In the onCreate() method of the main activity, I have the following code which adds some elements into the array list.
if (savedInstanceState == null){
Ipsum.Headlines.add("String 1 ");
Ipsum.Headlines.add("String 2");
}
savedInstanceState is a Bundle that the system passes to the method, if the app is being resumed from some inactive state. The logic is that if savedInstanceState is null, then the app is not being resumed but being started as a new instance.
If I leave the app using the "Home" button and re-enter the app, the arrayList contains only the two elements: "String 1" and "String 2". (This is the desired behavior)
However, if I leave the app using the back button, and then re-enter the app, the "String 1" and "String 2" elements are added again. The array then has 4 elements.
String 1
String 2
String 1
String 2
(The contents of the arrayList can be seen because they are used to populate a listView)
It seems that the app is storing the contents of the static array list when the back button is pressed.. and that a Bundle is not passed to the onCreate() method when the app is restarted. Can someone explain what's happening here, in terms of the app life cycle?
May This Help you:
Lets start with a bit of background: What happens when you start an application?
The OS starts a process and assigns it a unique process id and allocates a process table.A process start an instance of DVM(Dalvik VM); Each application runs inside a DVM.
A DVM manages class loading unloading, instance lifecycle, GC etc.
Lifetime of a static variable: A static variable comes into existence when a class is loaded by the JVM and dies when the class is unloaded.
So if you create an android application and initialize a static variable, it will remain in the JVM until one of the following happens:
1. the class is unloaded
2. the JVM shuts down
3. the process dies
Note that the value of the static variable will persist when you switch to a different activity of another application and none of the above three happens. Should any of the above three happen the static will lose its value.
For More Detail: Read the Answer of Samuh in this Link... Click Here
Your activity is being resumed. If you want to control what happens, implement onResume().
See Managing the Activity Lifecycle for details.
EDIT:
Static variables are a Java concept. static just means that there is only one copy of the variable for the whole class. The alternative is that each object would have it's own copy.
So while your code is running, you just have one copy of the variable in your program. It doesn't get saved anyplace, unless you add code to do that.
Static variables are associated with a class and they will live as long as the class is in the memory,and destroy when class gets unloaded (which very rarely happens). It can happen when-
-You force stop your app.
-Application crashes.
-You clear your app data.
-Switch off your Device(Shutdown DVM).
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.
I'm taking an android class now, so I am somewhat new to android app development.
My first assumption for a Base Activity is that it's Global Variables and it's values would be available to all activities. I have found that it is available to my Main Activity, but not any activities after that.
In the Base Activity I am storing an ArrayList of Objects. I also load data from an xml in there that adds objects to the arrayList. Once in the Main Activity I still have access to that arrayList and it's values. I use it to fill a list. But when I go to the next activity, it knows about the arrayList but thinks it is empty.
Do I need to create methods in the base activity to retrieve the arrayList and to add objects to the array list?
Any help would be appreciated.
Thank you,
Michelle
Global variables need to be declared static. Then they would be accessible from any class. Example:
public class Globals {
public static String myString;
}
Any class can read/write the myString like this:
Globals.myString = "foo";
or
String bar = Globals.myString;
From experience I believe the variables of one activity is only avaliable to the other while the activity is active, which means between onCreate and onDestroy, other then that you will probably get a null pointer exception, what you really should be doing is sending the data, or arrays, along with the intent to the other activity.
I dont think you should be calling on other activities variables, although it is possible as stated above. I believe when the activity has had it's onDestroy method called the objects in the activity are destroyed to and are removed from memory. Destroying anything that they held.
What is this base activity? Does it just extend activity? And then MainActivity is extending Activity as well? Only one activity is usable at any one time, if your doing what I think your doing you should have a service which can provide you with everything over the cycle of the application, just remember to stop it when your done with it.
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.