Change activity variables from another activity/Service - android

Following solutions are mostly suggested to do this:
using Intent like here
using Handler like here
using SharedPreferences like here
Question
What is the problem of defining a public method to set the variable like:
public class Activity1 {
private int var1;
public void setVar1(int val){
var1=val;
}
}
and in Activity2:
public class Activity2 {
Activity1.setVar1(4);
}
It seems that it is applicable for both static and non-static variables
EDIT1:
It is a simple case of my current project. In original case, the Activity2 connects to a bluetooth Hub and receives data of several sensors. If the values are changed, it should pass the changed values (and off course sensor ID's) to Activity1 which is responsible for updating UI. The number of sensors can be more than 100 and update period is in range of 100 msec, which means a runnable reads the incomming BT messages each 100 msec and checks changes.
EDIT2:
BroadcastReceiver is also solution. But the question is: Whats wrong with defining a set method to change/update a variable. Is this method inefficient in terms of memory? Does it makes the app slow? Is it an inappropriate code?
I just wanna know what kind of problems/inefficiencies I would face if I define set methods to change activity variables.

keep in mind that an Activity instance is itself a Context, and that these can be very heavy in terms of the amount of memory they occupy because they keep a reference to the Activity's view hierarchy and all its associated resources. retaining long-lived references to Activity instances is a common source of memory leaks.
keeping that in mind, in this particular setup:
public class Activity1 {
private int var1;
public void setVar1(int val){
var1=val;
}
}
...invoking activity1.setVar1(...) would imply that the running instance of Activity2 has a reference to an instance of Activity1, meaning the system hasn't been allowed to garbage collect it. this pattern could eventually lead to the application exhausting its heap and crashing.
you also inquired about the possibility of exposing these methods as static methods. while you'd avoid the aforementioned problem, one potential pitfall here is if a user switches to another application, and the system is running low on memory, your application process could be killed by the system. as static variables are tied to the running process instance, when the user returns to your application and the system restores its state, var1 would be reset to it's default value (zero). (you could probably mitigate this by hooking into the lifecycle methods to save values into a Bundle instance, etc).
those are some reasons i can think of to avoid writing getters/setters into your Activity's interface.

Having reference to another activity is not a good way to do it since each activity has it own life cycle. The activity that you are referring to probably get get destroyed or the system might already start a new instance of that activity whilst you still reference to the old one.
Alternatively, you can use event bus (Otto for example) to publish object/event to another activity.

Related

Retain singleton instance after thrown exception

I have created an Android application that uses a singleton to hold its state. The class is instantiated when the application starts.
The application does make extensive use of fragments but is not a single Activity application.
The problem occurs when an activity crashes for some (any) reason.
Normally, Android closes the activity bringing to the foreground the previous one that was active. Since the previous activity also used the singleton somehow, it needs data from it to resume (for example). The thing is that the singleton is no longer available while the previous activity is running in a new Application Context forcing the Singleton to re-instantiate itself with no data of course.
One way to surpass this problem seems to be storing the state (serialized or not) in a file or the database but that means too many read writes on pretty much every other user activity which should be avoided. Apart from UX, this solution might lead to inconsistent or erroneous data from faulty or untimely synchronisations.
I would like to hear your input on the matter.
Cheers!
Here is the Singleton instantiation method.
final public class Data {
private static Data INSTANCE = new Data();
private Data() {}
public static Data getInstance() {
return INSTANCE;
}
}
If you declare your singleton as static on a root activity it should be saved. We used static varaibles linked to a baseline activty from which every activity dereives.
Antoher solution might be to use sharedpreferences.
It is nice to worry about performance but if you have many fragments and few activities, it would be the fragment that will cause the lion share of teh workload
1) You can use an Application class. It's gonna be destroyed at the very last stage.
2) If your data is not structured - you can keep it in SharedPreferences (as a String mapped with JSON for example)
3) If your data is structured - you should store it in DB (or better ContentProvider)

Main data model on android

I have an android application with a number of activities.
I have a singleton class holding my main data model which all activities access to get data.
The problem is that sometimes the android GC decides to destroy my singleton when the app in the background (when you press the home button).
Is there anyway that I can bypass this?
I've had this exact problem in a current application of mine, which needs to retain a large amount of data in various 'singleton' classes. The problem I encountered was as in your case; i.e. sometimes when bringing the application back to the foreground, some of the static 'singleton' classes have been destroyed.
The problem, I believe, is that the 'lifetime' of such classes can never be well defined or predicted. After all, it's a class sat there holding a reference to itself, so it's susceptible to being garbage collected when the system wants to grab some resources.
You're probably already aware that extending android.app.Application is a well-known alternative to using conventional Singletons. The solution that worked for me is to hold the actual instances of data singleton classes within an extension class of android.app.Application, whose lifecycle is well defined. Any other class that wants to access those singletons can obtain them using a getter in the Application class.
So for example I have a class called AppState that extends Application, that holds the instances within:
import android.app.Application;
public class AppState extends Application {
...
// "Singleton" instances that this Application extension looks after
private MSData singletonInstanceMSData;
public AppState() {
...
singletonInstanceMSData = new MSData();
...
// ---------------- Singleton instance control ----------------
public MSData getMSData(){
return singletonInstanceMSData;
}
// I also provide the means to 'reset' the instances on startup (this is
// something I need to do for my application - you may or may not need to)
public void resetControllerSpecificData(){
singletonInstanceMSData.reset();
...
Don't forget you'll need to modify your manifest if you extend Application.
AFAIR, lifespan os singleton is lifespan of his classloader - also complete VM . When user hit home button, your application goes in backgorund and is probably destroyed - you can not do anything against it. Your best bet is to save whatever is necessary in your onPause() callback ( or just use write through in every change of datza if you really paranoid )

Could the values on global variables have been reset when an Android app resumes?

When an app have been put into the background and later resumes to an activity, is it possible that static class variables set in another Activity could have been reset by the garbage collector and have got the value set to zero?
I use a couple of public static int variables in my main Activity and use them as global variables in various other Activities. I have received a crash report in the developer console from Android Market where the only explanation I can find is that the app resumes to an Activity which uses the value of a public static int variable in another class, but the value has (mysteriously?) become zero. I know that it was set to something else when the app first started. Is this at all possible?
If my suspicion is correct, what is the recommended way to preserve the values of the global variables when an app is put in to background? Save them in SharedPreferences in OnPause() or use onSaveInstanceState or something else?
When an app have been put into the background and later resumes to an activity, is it possible that static class variables set in another Activity could have been reset by the garbage collector and have got the value set to zero?
It would not be "reset by the garbage collector". However, the process may have been terminated by Android, to free up memory for other applications.
what is the recommended way to preserve the values of the global variables when an app is put in to background?
Static data members should only be a cache. Data you want to retain regardless of what happens (e.g., process being terminated) needs to go in some persistent store, such as a flat file, SharedPreferences, or database. onPause() is a likely time to arrange to persist that data, as any time after that, your process could be terminated without notice.
Be careful with static variables. Follow the link for an explanation concerning Singleton (which also use a static variable to maintain state): https://stackoverflow.com/a/9004638/1127492
You can save this values on SQLite on method onDestroy in activity or another method with response to exit.

Android: is it possible to refer to an Activity from a 2nd Activity?

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

Using the Android Application class to persist data

I'm working on a fairly complex Android application that requires a somewhat large amount of data about the application (I'd say a total of about 500KB -- is this large for a mobile device?). From what I can tell, any orientation change in the application (in the activity, to be more precise) causes a complete destruction and recreation of the activity. Based on my findings, the Application class does not have the same life-cycle (i.e. it is, for all intents and purposes, always instantiated). Does it make sense to store the state information inside of the application class and then reference it from the Activity, or is that generally not the "acceptable" method due to memory constraints on mobile devices? I really appreciate any advice on this topic. Thanks!
I don't think 500kb will be that big of a deal.
What you described is exactly how I tackled my problem of losing data in an activity. I created a global singleton in the Application class and was able to access it from the activities I used.
You can pass data around in a Global Singleton if it is going to be used a lot.
public class YourApplication extends Application
{
public SomeDataClass data = new SomeDataClass();
}
Then call it in any activity by:
YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.
I discuss it here in my blog post, under the section "Global Singleton."
Those who count on Application instance are wrong. At first, it may seem as though the Application exists for as long as the whole app process exists but this is an incorrect assumption.
The OS may kill processes as necessary. All processes are divided into 5 levels of "killability" specified in the doc.
So, for instance, if your app goes in the background due to the user answering to an incoming call, then depending on the state of the RAM, the OS may (or may not) kill your process (destroying the Application instance in the process).
I think a better approach would be to persist your data to internal storage file and then read it when your activity resumes.
UPDATE:
I got many negative feedbacks, so it is time to add a clarification. :) Well, initially I realy used a wrong assumption that the state is really important for the app. However if your app is OK that sometimes the state is lost (it could be some images that will be just reread/redownloaded), then it is fully OK to keep it as a member of Application.
If you want to access the "Global Singleton" outside of an activity and you don't want to pass the Context through all the involved objects to obtain the singleton, you can just define a static attribute in your application class, which holds the reference to itself. Just initialize the attribute in the onCreate() method.
For example:
public class ApplicationController extends Application {
private static ApplicationController _appCtrl;
public static ApplicationController getAppCtrl()
{
return _appCtrl;
}
}
Because subclasses of Application also can obtain the Resources, you could access them simply when you define a static method, which returns them, like:
public static Resources getAppResources()
{
return _appCtrl.getResources();
}
But be very careful when passing around Context references to avoid memory leaks.
Dave, what kind of data is it? If it's general data that pertains to the application as a whole (example: user data), then extend the Application class and store it there. If the data pertains to the Activity, you should use the onSaveInstanceState and onRestoreInstanceState handlers to persist the data on screen rotation.
You can actually override the orientation functionality to make sure that your activity isn't destroyed and recreated. Look here.
You can create Application class and save your all data on that calss for use that anywhere in your application.
I know this is the very old question but using the ViewModel from the jetpack components is the best way to preserve the data between Activity rotation.
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

Categories

Resources