I need to keep a reference to an object between different activities. The two said mentions seem to create new objects from activity to activity. This is a problem because changes to the object in the "child" activities don't persist once the parent activity gets focus. My solution to this was just to create a static getter in the parent-most activity which the child activities call and work with. Is this the incorrect way to go about this?
If you want to share a single instance of an object between activities, you can create a singleton class. The only thing wrong with using your parent-most activity class to implement the singleton might be that it might violate the single responsibility principle.
You can make your object persistent throughout the whole application lifecycle by making it a field in your Application-derived class.
public class MyAppication extends Application {
private Object mMyData;
public setData(Object data) {
mMyData = data;
}
public Object getData() {
return mMyData;
}
}
Then ((MyApplication)getAppllication()).setData or getData()
This way you can exchange data within the application because MyApplication will always exist.
You'll also have to add MyApplcation to manifest
You should create a Singleton, this has a single instance whenever you talk to it. (Just like your describing).
Here's one I made earlier : https://stackoverflow.com/a/6539080/413127
Related
I have:
public MissionActivity extends AppCompatActivity {
public SoundPlayer getSoundPlayer();
public DiffrentSoundPlayer getDiffrentSoundPlayer()
//...etc.
}
I am passing this Activity in constructor to another class that need all
this soundplayers and assetManager. All these players need to be created in activity. My question is: is this a good practice in Android to pass reference to Activity to another object?
Passing the activity is not in itself problematic, but given the scope of activities is something that should be done thoughtfully.
Depending on your specific case I would consider wrapping the objects that you have created on the activity inside a data transfer object and pass that object to the class that needs the objects. And by "data transfer object" I simply mean an object whose sole purpose is to store the data/objects that you are transferring.
But simply passing the activity to the other class is also completely okay, as long as you don't store the activity in that other class (just store the objects that you need from the activity).
While I was coding, I wanted to use findViewById method to find a view that cant access in the current view but can be accessed via the MainActivity. So two options came to my mind. One is creating a static method from that object in the MainActivity class and access the static object. The second method is to create a static object form MainActivity class itself(this) and access the findViewById method by calling the static object. Please answer the method I should use.
And apart from that, it got me thinking that whether an Android developer should come across this type of scenario or whether I have done some improper coding to access findViewById method in MainActivity while I was in a different view.
You can take a look at the code in the below repo.
https://github.com/chrish2015/ExpenseTrackerLatest
Thanks
If you are inside a class that is neither a Context nor an Activity and you need to use a method which exists inside the activity or context, then simply pass the activity as a parameter to that class and take an instance to that activity inside your class.
public class MyAdapter extends ArrayAdapter { // this is not activity
private Activity mActivity; // activity is a member of this class.
public MyAdapter(Activity activity, List<String> data) {
mActivity = activity;
}
public View getView(...) {
// if you need to use findViewById:
View view = mActivity.findViewById(R.id.some_id);
}
}
Don't use any of your two methods.
I might be misunderstanding your first sentence, but just to be sure, are you asking for a way to access a View that exists in the MainActivity, while you're inside of a Fragment?
If that's what you're asking, then yes, as an Android Developer, there will definitely be moments where we come across this scenario. However, the solution is definitely NOT by making your Views or Context static.
This is one of the easiest ways to cause bugs to appear throughout your app, with a very high chance to cause memory leaks too. Here's an Article from Google talking about memory leaks related to keeping a reference to a Context: https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html
Rather than your two options, there are better solutions that developers typically use.
First of all, keep in mind that you should NOT be directly accessing any Views from outside of your current layout... meaning, that if you're in a second Activity, you don't directly access Views from the first Activity, or if you're in a Fragment, you don't directly access Views that belong to it's FragmentActivity.
Instead, you let the Activity or Fragment handle it's own Views.
So for example, if you're in another Activity and you want to update some data in the previous Activity, you can take advantage of an Activity's startActivityForResult() and onActivityResult() to obtain the data necessary to update the Activity immediately upon returning to the app.
For Fragments, there's actually a tutorial from the Android Documentation that describes a very good way to communicate between other Fragments: https://developer.android.com/training/basics/fragments/communicating
This method is to use interfaces as a callbacks, so another Fragment or the Activity will be able to receive data and update it's Views within it's own layout.
So for your case, if you're using Fragments and an Activity, you can easily have your fragments and activities communicate to each other in a safer and more reliable way.
Also, make sure you read up more on static and it's effects on your code, especially the side effects on Android components. Do not carelessly use static without considering some of the effects it might cause, because that would cause an endless amount of trouble to your code.
An extended Application class can declare global variables. Are there other reasons?
Introduction:
If we consider an apk file in our mobile, it is comprised of
multiple useful blocks such as, Activitys, Services and
others.
These components do not communicate with each other regularly and
not forget they have their own life cycle. which indicate that
they may be active at one time and inactive the other moment.
Requirements:
Sometimes we may require a scenario where we need to access a
variable and its states across the entire Application regardless of
the Activity the user is using,
An example is that a user might need to access a variable that holds his
personnel information (e.g. name) that has to be accessed across the
Application,
We can use SQLite but creating a Cursor and closing it again and
again is not good on performance,
We could use Intents to pass the data but it's clumsy and activity
itself may not exist at a certain scenario depending on the memory-availability.
Uses of Application Class:
Access to variables across the Application,
You can use the Application to start certain things like analytics
etc. since the application class is started before Activitys or
Servicess are being run,
There is an overridden method called onConfigurationChanged() that is
triggered when the application configuration is changed (horizontal
to vertical & vice-versa),
There is also an event called onLowMemory() that is triggered when
the Android device is low on memory.
Application class is the object that has the full lifecycle of your application. It is your highest layer as an application. example possible usages:
You can add what you need when the application is started by overriding onCreate in the Application class.
store global variables that jump from Activity to Activity. Like Asynctask.
etc
Sometimes you want to store data, like global variables which need to be accessed from multiple Activities - sometimes everywhere within the application. In this case, the Application object will help you.
For example, if you want to get the basic authentication data for each http request, you can implement the methods for authentication data in the application object.
After this,you can get the username and password in any of the activities like this:
MyApplication mApplication = (MyApplication)getApplicationContext();
String username = mApplication.getUsername();
String password = mApplication.getPassword();
And finally, do remember to use the Application object as a singleton object:
public class MyApplication extends Application {
private static MyApplication singleton;
public MyApplication getInstance(){
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton = this;
}
}
For more information, please Click Application Class
Offhand, I can't think of a real scenario in which extending Application is either preferable to another approach or necessary to accomplish something. If you have an expensive, frequently used object you can initialize it in an IntentService when you detect that the object isn't currently present. Application itself runs on the UI thread, while IntentService runs on its own thread.
I prefer to pass data from Activity to Activity with explicit Intents, or use SharedPreferences. There are also ways to pass data from a Fragment to its parent Activity using interfaces.
The Application class is a singleton that you can access from any activity or anywhere else you have a Context object.
You also get a little bit of lifecycle.
You could use the Application's onCreate method to instantiate expensive, but frequently used objects like an analytics helper. Then you can access and use those objects everywhere.
Best use of application class.
Example: Suppose you need to restart your alarm manager on boot completed.
public class BaseJuiceApplication extends Application implements BootListener {
public static BaseJuiceApplication instance = null;
public static Context getInstance() {
if (null == instance) {
instance = new BaseJuiceApplication();
}
return instance;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onBootCompleted(Context context, Intent intent) {
new PushService().scheduleService(getInstance());
//startToNotify(context);
}
Not an answer but an observation: keep in mind that the data in the extended application object should not be tied to an instance of an activity, as it is possible that you have two instances of the same activity running at the same time (one in the foreground and one not being visible).
For example, you start your activity normally through the launcher, then "minimize" it. You then start another app (ie Tasker) which starts another instance of your activitiy, for example in order to create a shortcut, because your app supports android.intent.action.CREATE_SHORTCUT. If the shortcut is then created and this shortcut-creating invocation of the activity modified the data the application object, then the activity running in the background will start to use this modified application object once it is brought back to the foreground.
I see that this question is missing an answer. I extend Application because I use Bill Pugh Singleton implementation (see reference) and some of my singletons need context. The Application class looks like this:
public class MyApplication extends Application {
private static final String TAG = MyApplication.class.getSimpleName();
private static MyApplication sInstance;
#Contract(pure = true)
#Nullable
public static Context getAppContext() {
return sInstance;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() called");
sInstance = this;
}
}
And the singletons look like this:
public class DataManager {
private static final String TAG = DataManager.class.getSimpleName();
#Contract(pure = true)
public static DataManager getInstance() {
return InstanceHolder.INSTANCE;
}
private DataManager() {
doStuffRequiringContext(MyApplication.getAppContext());
}
private static final class InstanceHolder {
#SuppressLint("StaticFieldLeak")
private static final DataManager INSTANCE = new DataManager();
}
}
This way I don't need to have a context every time I'm using a singleton and get lazy synchronized initialization with minimal amount of code.
Tip: updating Android Studio singleton template saves a lot of time.
I think you can use the Application class for many things, but they are all tied to your need to do some stuff BEFORE any of your Activities or Services are started.
For instance, in my application I use custom fonts. Instead of calling
Typeface.createFromAsset()
from every Activity to get references for my fonts from the Assets folder (this is bad because it will result in memory leak as you are keeping a reference to assets every time you call that method), I do this from the onCreate() method in my Application class:
private App appInstance;
Typeface quickSandRegular;
...
public void onCreate() {
super.onCreate();
appInstance = this;
quicksandRegular = Typeface.createFromAsset(getApplicationContext().getAssets(),
"fonts/Quicksand-Regular.otf");
...
}
Now, I also have a method defined like this:
public static App getAppInstance() {
return appInstance;
}
and this:
public Typeface getQuickSandRegular() {
return quicksandRegular;
}
So, from anywhere in my application, all I have to do is:
App.getAppInstance().getQuickSandRegular()
Another use for the Application class for me is to check if the device is connected to the Internet BEFORE activities and services that require a connection actually start and take necessary action.
Source: https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class
In many apps, there's no need to work with an application class directly. However, there are a few acceptable uses of a custom application class:
Specialized tasks that need to run before the creation of your first activity
Global initialization that needs to be shared across all components (crash reporting, persistence)
Static methods for easy access to static immutable data such as a shared network client object
You should never store mutable instance data inside the Application object because if you assume that your data will stay there, your application will inevitably crash at some point with a NullPointerException. The application object is not guaranteed to stay in memory forever, it will get killed. Contrary to popular belief, the app won’t be restarted from scratch. Android will create a new Application object and start the activity where the user was before to give the illusion that the application was never killed in the first place.
To add onto the other answers that state that you might wish store variables in the application scope, for any long-running threads or other objects that need binding to your application where you are NOT using an activity (application is not an activity).. such as not being able to request a binded service.. then binding to the application instance is preferred. The only obvious warning with this approach is that the objects live for as long as the application is alive, so more implicit control over memory is required else you'll encounter memory-related problems like leaks.
Something else you may find useful is that in the order of operations, the application starts first before any activities. In this timeframe, you can prepare any necessary housekeeping that would occur before your first activity if you so desired.
2018-10-19 11:31:55.246 8643-8643/: application created
2018-10-19 11:31:55.630 8643-8643/: activity created
You can access variables to any class without creating objects, if its extended by Application. They can be called globally and their state is maintained till application is not killed.
The use of extending application just make your application sure for any kind of operation that you want throughout your application running period. Now it may be any kind of variables and suppose if you want to fetch some data from server then you can put your asynctask in application so it will fetch each time and continuously, so that you will get a updated data automatically.. Use this link for more knowledge....
http://www.intridea.com/blog/2011/5/24/how-to-use-application-object-of-android
So I have 3 Activities that need to all have access to the same custom class object (let's call it 'a') created by me when the very first Activity is created.
Because 'a' is made up of a whole bunch of non-primitives, I found it difficult to make Serializable or Parcelable. Instead I created a Service that binds to each Activity as they take the forefront, and gives the Activity 'a' in OnBind().
Now 'a' has a getter that gets another object of a different custom class stored with the same object (let's call it 'b'). In all three Activities, I also need to be able to access 'b'.
If I start the first Activity, use a button to navigate to the second Activity, press the "home" button on my phone, then go back into the application by pressing its icon, then navigate to the third activity by pressing a button, I get a null pointer exception on 'b' but not 'a'.
However if I add a line that prints 'a's getter for 'b' with sysout in the step where I press a button to get from the second Activity to the third, then there is no null pointer exception.
Does anybody know why this is and how I can resolve the issue?
Seems you want this object a to always be there!
I suggest extending application
public class YourApplication extends Application {
YourObject A;
#Override
public void onCreate(){
A = new YourObject();
}
//add getters or setters //
}
Now in your Activities:
YourApplication app;
app = app = ((YourApplication)getApplicationContext());
Finally in your Mainfest: Add to <application>
android:name=".YourApplication"
Sounds like you may want to consider a singleton class. An example (and description) in Java is here, but it boils down to:
public class ClassicSingleton {
private static ClassicSingleton instance = null;
protected ClassicSingleton() {
// Exists only to defeat instantiation.
}
public static ClassicSingleton getInstance() {
if(instance == null) {
instance = new ClassicSingleton();
}
return instance;
}
}
Now, when you want to access the singleton object, just use:
ClassicSingleton instance = ClassicSingleton.getInstance();
Sherif's solution would also work (and I was going to suggest this first, myself), but I prefer the singleton route as it's a little cleaner from an OO perspective.
Singletons have (at least) the following benefits over a global object:
Singletons use lazy instantiation so they are only created when they are first accessed, not when defined. If your object is costly to instantiate or maintain, it may be better to use a singleton rather than having it around for the life of the app
You can guarantee there will always be only one instance of a singleton - a global object can have as many instances as you have resources for
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