Singletons not available when the App comes back to memory - java

The problem I'm facing is the following: When I start my app all the singletons get initialized in the main activity and everything works as expected. Then if I press the home buttom and comeback to the app quickly everything works, I think it's because everything is in memory yet, but if I go to chrome watch a couple of videos or start a game and try to get back to my app I get an exception. I don't understand this state of the app because it's not killed but it's not in memory and it tries to get back to the activity it was before pressing the home buttom, the onCreate method is called and I receive the Intent which called the activity in the first place but singletons are not initialized, the exception occurs here:
Tracker tracker = GoogleAnalytics.getInstance(this).getDefaultTracker();
tracker.set(Fields.SCREEN_NAME, "My View");
tracker.send(MapBuilder
.createAppView()
.build()
);
A possible solution I tried is just checking the tracker and if it is null create a new one and set it:
if(tracker == null){
tracker = GoogleAnalytics.getInstance(this).getTracker(trackerId);
GoogleAnalytics.getInstance(this).setDefaultTracker(tracker);
}
But I get another exception in another singleton. My question is: what variables are kept in memory when the app is in this state? What should I do, maybe call finish when the tracker is null? or Intent the main activity?

Simply the Android system doesn't insure anything staying in memory forever, whenever the system needs memory it's gonna start clearing background apps and services according to priority.
One approach is you can make the getters of the singletons handle that, if the instance variable in your singleton is null or not initialized, then you should initialize it, that could solve your problem and it will add a lazy initialization flavor to your approach.
Another is you can add a flag in onSaveInstance() and you can check it in your onCreate(), then you'll know if this is the first time for your activity to start or it has been cleared from memory and is being reinitialized.

Try using finish() and also add the try catch method in If condition

Related

What exactly happens with static variables and services when the MainActivity is destroyed by the Back-Button and then recreated?

I would like to understand better what exactly is Happening when the Back-button is pressed and the MainActivity is destroyed in Terms of static variables and registered services.
this is what i know already:
onDestroy() will be called.
the activity is still listed when you hit the overview-button (the same as if ou hit the home-button or switch to another activity). When you activate it again, onCreate() is called.
What I Need to know is:
1.) what happens with static variables which are declared and initialized globally.
i.e.
static boolean logging_on_flag = false;
this is turned to true when the app is running, but if the activity is detroyed by the back-button and then recreated, will it be true or false?
2.) What happens with registered Services (listeners)?
i.e., I use Location Services to log my Location data. After registrating the Location listener, the System calls the method onLocationChanged() every time the Location changes. In that method, i do the logging.
When i leave the app with the back-button, will this process be interrupted? will the listener be unregistrated?
I am confused and forced to ask the experts here, since the back-button-behaviour of my app changed since I started to work with Fragments.
Before:
leaving the app with the back-button did not Interrupt the logging process, but the non-static variables were reinstanciated when the activity was selected again. Since the listener was bound to the old variable instances, changing the new instances did not have any effect on the logging process anymore. Furthermore, the listener would be registrated again because this is Happening in onCreate(), which lead to dual logging (every measurement was logged twice).
I could solve this by making the logging_flag static (which prevented instanciating) and checking in onCreate() if the flag is already true and if this is the case, the listener was not registrated again. This worked like a charm, since the flag remained true after recreating.
After implementing Fragments here and there:
The behaviour on leaving the app by pressing the back-button seems to have changed completely. Now, the logging is stopped immediately as the back-button is pressed and when you get back to the app, it is completely restarted and even the static variable was not true anymore but false.
Can anybody explain me, why the behaviour has changed in Terms of the static variables and the services?
Please note that this is a General question to get a better understanding of the back-button. I am not asking for a solution (and yes, I know I should better work with savedInstanceState).
statics are not part of the object so they still alive until you assign null to them. Or kill application.
Answering your question:
1) static will contains last value
2) Listener will be working until you kill app. You must unregister listeners on close.
Why behavior change? It didn't change. I think you have made somewhere mistake, but can't tell without seeing code.
what happens with static variables which are declared and initialised
globally.
They live as long as your the app process is living. When you go back to the home screen of the system, the app process is not necessary killed (it's managed automatically by the system if it considers it has enough resources or not). So potentially your static variable can still have the value you've set, the next time you launch the app.
What happens with registered Services (listeners)?
Depending on how you've started the service, it can still run in the background even if you don't need it!. So don't forget to stop everything when the app is stopped.
Concerning the listeners, they will still be affected to the service so it can create memory leaks if you've forgotten to un-register them.
Conclusion
You should avoid to use static variable to store data (you can use final static as constants).
You should use onPause to stop services / unregister listeners... and onResume to restart them.

invoke a method from activity in another

i know that this question was asked before but i had tried all the solution and get Error
i have two activity on android studio ...
the first called 'MainActivity' and contain a method ' deleteFromArrayList() '
the secound on called 'DeletButtonActivity' and contain a method ' delete(View v) '
i want to invoke 'deleteFromArrayList ()' wihtout creating another class or make the method static .... becouse i have an ArrayList inside deleteFromArrayList()
note : i send value of index i want to delete from array list using Intent ..the code in DeleteButtonActivity is
public void delete(View v) {
try {
Intent i = new Intent(DeleteButton.this, MainActivity.class);
i.putExtra("index", (int) spinner2.getSelectedItemId());
(new MainActivity()).DeletButtonActivity();
Toast.makeText(getApplicationContext(), "it was deleted", Toast.LENGTH_SHORT).show();
}
catch(Exception e){
Toast.makeText(getApplicationContext(), e+"", Toast.LENGTH_SHORT).show();
}
}
and the code in MainActivity
public void deleteFromArrayList (){
this.arrayList.remove(getIntent().getIntExtra("index",-1));
}
when i run the app i got an Error NullPointerException,,,
can anyone help me ..please
hope that i describe the problem very well
Activities in Android are no just a simple class but they also have a Lifecycle:
An activity has essentially four states:
If an activity is in the foreground of the screen (at the top of the
stack), it is active or running. If an activity has lost focus but is
still visible (that is, a new non-full-sized or transparent activity
has focus on top of your activity), it is paused.
A paused activity is
completely alive (it maintains all state and member information and
remains attached to the window manager), but can be killed by the
system in extreme low memory situations.
If an activity is completely
obscured by another activity, it is stopped. It still retains all
state and member information, however, it is no longer visible to the
user so its window is hidden and it will often be killed by the system
when memory is needed elsewhere.
If an activity is paused or stopped,
the system can drop the activity from memory by either asking it to
finish, or simply killing its process. When it is displayed again to
the user, it must be completely restarted and restored to its previous
state.
So the problem with your code is that when you want to access the array in a stopped activity, the instance you have been using before might not be alive anymore.
How to solve your problem
A very simple approach is to use parameter passing before you do the transition from one activity to the other, for this you'd pass your Array as an intent extra and then you "get the result back" when you finish the second activity by using onActivityResult() callback.
A second approach could be to use a Service that is something similar to an Activity but it has no UI and it has its own lifecycle. Being able to be alive even when you app it is not. Using a Service, you'll keep the Array inside the service and you'll communicate with the array to do the usual operations.
A third approach could be to use an EventBus. A very simple communication mechanism between Activities, Fragments, Threads, Services. There's a great talk titled Android Application Architecture on Android Dev Summit 2015 that uses EventBus as a communication mechanism and to implement a MVC architecture pattern on a REST Android App.
Back to your question. If you just need to 'share' an array between two activities, use the first approach. The second and third are just examples of different alternatives for the case you need a lot more than that.
You must not do this. There are mechanism to communicate between activities or fragments.
On can be, using startActivityForResult, this is Activity A calls Activity B, then in B you do something, and communicate the result back to Activity A.
You can have another workaround to what you want. If you can access the data in both of your activities, you can modified in ether one of them, when the activity starts, it will show the updated data.
Please first read well about an Activity here, and also provides more context of your question.

Android task lifecycle and static data, is a task ever destroyed?

Android activities have a well defined lifecycle and they will be paused, stopped, and destroyed. That is very well documented. My question is about the task that contains my activities as described in the docs.
Under low memory or other conditions, will the task ever be shut down by the OS? (I understand the user can Force Stop the app).
Can I assume my Singletons and static data will always be available?
What about static members defined on an Activity? It appears that the Activity may be destroyed, but the static data lives as long as the task lives.
android.app.Application has callbacks like onLowMemory() and onTrimMemory() but these seem to be voluntary, meaning it is great if the app cooperates with the OS, but it doesn't have to. So, I'm pretty certain my task is never normally killed and singletons and statics are reliable. Is this correct?
This answer also had some good background.
I was extremely curious about your question and so I quickly did a simple check with a very simple project and I'll post what I found - I'll answer the rest based on hypotheses as Android's clean up process is quite arcane.
Created 3 activities - A, B, C. A can call B or C. A is the starting
point of the app. B and C cannot call anything. C has a static
integer member x.
x is a class member of C and initially does not have any value. I set
it to 5 and printed it out in the onCreate() of C. It is also printed
out in the onResume() of A.
When I started the app, a toast was displayed on A which said 0 (C.x
has not been set yet). Then I navigate to C. I get a toast c=5.
Then I press back and go back to A. I get a toast c=5. C has been
destroyed.
Then I go to B. No toast. Go back to A. I get a toast c=5.
From A, I press home. From home, I again reopen the activity. I get
c=5.
I press back to go back to home (destroying A). Then I reopen the
app. I get c=5.
Then I go back and force stop the app from settings. Then I reopen
the app - I get c=0. Force stop completely removes everything from this task.
From this, you can say that static values continue to exist even after the Activity has been destroyed. Even after an application is closed, the value is still retained by Android.
Can I assume my Singletons and static data will always be available?
I would say that you can assume this as long as Android is not pushed to the point where it decides that memory needs to be reclaimed.
From the Android tutorial book by Commonware, I understand that any task that is running in the background is considered as an important task and will not be shut down by Android. But if another task comes to the foreground, then this is given a higher priority and all tasks in the background assume lower priority. If Android decides the task in the foreground needs more memory, it will start killing processes based on order of priority which depends upon a number of factors. Under low memory conditions, any task can be killed. In extreme cases, the task on the foreground itself may be killed.
I hope this answers your question. It certainly piqued my interest.
Can I assume my Singletons and static data will always be available?
You can never assume that. Sometimes contex changes (when you go to the settings and turn gps on for instance) and then your apps is being recreated. OS can destroy your activity in any time. You should never operate on static data even on PC programs
It seems that the OS can kill your task in low memory and other situations. And, of course, your statics and singletons die with the task.
If you need your statics and singletons to survive task shutdown and restart, you need to persist them somewhere. Android Application Framework FAQ has good suggestions. I found that you can leverage onSaveInstanceState() and save your data as part of the save instance bundle. It will be restored when the Activity is restored. See Controlling Android Activity restart after a process stops

ANR problem in my app

I have quite a heavy Activity with a lot of things going on in the UI Thread, and also other Runnable threads within the Activity. Within this main activity I start a new Activity with a button press which is called using startActivityForResult(). Now when I start the new activity I get an ANR error meaning that there is something taking longer than the set amount of time and I get the ForceClose/Wait Dialog pop up.
The thing is, for the new Activity I am only setting the contentView for the activity and nothing else so it means something from the previous Activity is causing it to hang. It has never down this before in the app only recently and I can't think what I have added for it to cause this.
In the first Activity I have OpenFeint, SurfaceHolder.Callback, database calls in background thread and lot's of image manipulation. Are any of these processes hungry enough to cause the ANR?
Could I possibly put the first activity on hold while the second one loads (I thought it did that anyway)? Like I say the second Activity does nothing other than load a ContentView.
When you start a new activity, the previous activity should be put on hold, as you say. But first the activity's onPause is called. Maybe it's this method which causes the ANR? Especially if it is saving large amounts of state data.
Just guessing here.
The fact that there is an ANR it is pretty clear that something is running longer in the UI thread (as you have pointed out). Also, you seem to be doing a lot of things (at least the explanation gives this feeling). At this point I can say try commenting out certain parts and see if the problem persists. E.g. comment the startActivityForResult(), this should tell you which activity is the culprit. Also, if you can put up some pseudo code, I'm sure people would get a better idea and would be able to help better.
The ANR occurs usually when you solicit the UI (like pressing a button), so I think it's not the second activity launch which causes the ANR, but the fact you use the UI.
So the problem is from your first activity, not the second.

Android App/Activity To Start Fresh Completely every time it starts or resumes?

I have a kid's app for Android and there are some unique considerations for this application since the app has basically no navigation (it's for young kids). I do not want to break my app UI (which has been successful on iPhone) by adding a quit/restart button.
What I really need is fairly simple -- I want my activity/app to start clean and new every single time it starts. Whether it's an initial load or whatever -- basically any time onResume is called I want a completely fresh instance of my app.
I initially thought I could just exit/quit/finish the app when the user leaves. But I haven't found a way to do this that doesn't cause crashes on start. Also every thread/stack overflow post about that idea is filled with people wagging their fingers and saying you should never ever quit an app on android.
If I can't quit the app onExit, is there something I can do to restart my activity every time onResume is called? (or would that be an infinite loop?).
Would greatly appreciate any help!
Try starting your main activity in onResume, and clearing the activity stack:
public void onResume() {
super.onResume();
startActivity(new Intent(this, MainScreen.class).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
maybe these aren't the correctl flags to add, but check out the other Intent flags and this could do what you want!
intent flags documentation
Ended up getting it to work fine by calling finish() in onPause().
Again, I appreciate the advice from people saying "this is not how Android does things". I've got a pretty good understanding of the best practices at this point. This is an unusual situation for an unusual type of user.
in your reload you can try this..
onStop();
onCreate(getIntent().getExtras());

Categories

Resources