Click on item leads to IllegalStateException - java

How can this happen? I use a RecyclerView in an fragment and the fragment itself implements my click listener...
Sometimes, clicking an item in the list results in following error:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
How can this happen? Clicks should be forwarded to their handlers synchronous and this should not happen, should it?

Some code fragment would really help. But your error already states Can not perform this action after onSaveInstanceState
This means that after the function onSaveInstanceState() has been called, you try to do something. Put that code before onSaveInstanceState() and you might have a solution.

OnSaveInstance is called when the activity is about to be destroyed.
The android gives a last attempt to save all the data in a bundle that can be retrived back when the activity is recreated onRestoreInstance.
Mostly this case occurs when the android decide to garbage collect your activity due to lack of memory.
The error state that you are doing some work on UI -fragment after the onSaveInstance has been called.
Android does not allow any work on fragments after this has been called and soon onDestroy will be called.
So kindly revisit your logic or place a isFinishing() check before doing any work.

Actually it's because you're activity is getting destroyed due to lack of memory and before it gets destroyed it saves the fragment state also, and like you mentioned it happens sometine, during this you might have clicked your own which tried calling that previous state non click on the destroyed fragment.
How can you avoid it
Use volley and Picasso. And check which part of your application is using more memory using memory monitor given in android studio.
Also if you are not able to reduce memory usage consider adding.
large heap="true"
in your manifest

Related

What happens when we call finish() in onCreate() method?

What happens when we call the finish()method for the activity inside onCreate()?
Will the app get time to display the Activity, but then rapidly close, or won't it show anything?
This is just a doubt that I had before reading about some malware services for android that allegedly use this idea... Does it effectively work?
I just tested and debugged it, the Activity starts but is immediately closes once the event is generated.
As MrMins mention it will rapidly close. The lifecycle will skip over some important steps, therefore causing potential issues.
But to answer you question it will run only momentarily.
Here is the android documentation of the lifecycle: https://developer.android.com/guide/components/activities/activity-lifecycle.html
As per official documentation:
You can call finish() from within this function, in which case onDestroy() will be immediately called after onCreate(Bundle) without any of the rest of the activity lifecycle (onStart(), onResume(), onPause(), etc) executing.
Since
The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop().
so the "visible lifetime" is not reached for that case.

How is an Android Activity recreated when the screen is rotated?

I'm a newbie Android developer. I know that when the screen orientation changes, the Activity is re-created and onCreate() is called again. What I couldn't find online, however, is how exactly the original Activity is destroyed. If some code called by onCreate() is in the middle of running, does that code just stop, or does the system wait for that code to finish before rotating the screen and calling onCreate() again? Thanks.
Activity's onCreate() is called everytime when the orientation changes and you should take care of your asynchronous task because the system does not wait, but you can avoid the re-creation of Activity by adding configChanges attribute of Activity in your AndroidManifest file in the activity tag.
android:configChanges="keyboardHidden|orientation"
According to the official documentation on configuration changes, once a device rotation is detected or the activity is started for the first time, onCreate() is called; you should assume that for all intents and purposes the onCreate() method will complete its execution before another screen rotation triggers activity recreation. Any code executed in your onCreate() should be done instantaneously since it shouldn't block your UI.
When rotating a screen we call it one of the Configuration Changes, it includes situations such as screen orientation, keyboard availability, and language changes. As quoted from Android official documentation here onDestroy() will be called then onCreate().
Some device configurations can change during runtime (such as screen orientation, keyboard availability, and language). When such a change occurs, Android restarts the running Activity (onDestroy() is called, followed by onCreate()).
But if there was any code executing on the main thread will have to finish (not other threads) and Android gives you time to save the activity data which you can receive on onCreate() when the activity is restarted. It does so by calling the method by calling the method onSaveInstanceState() as explained here in the documentation.
To properly handle a restart, it is important that your activity restores its previous state through the normal Activity lifecycle, in which Android calls onSaveInstanceState() before it destroys your activity so that you can save data about the application state. You can then restore the state during onCreate() or onRestoreInstanceState().
So the whole issues of code in the activity is that it will wait for the code to finish if it were executing on the main thread and if the code taking too slow it may make configuration changes very slow as it is discouraged in the documentation to make huge tasks in the main thread (for instance http requests).
This whole answer and descriptions and quotes has been taken from Android Official Documentation Guide, you can visit it for reference and more descriptions on configuration changes.

Is there a way to restart the application instead of having it restart the last activity after a crash?

Since I store certain information that is necessary in my Application class, when a user encounters a crash, sometimes they encounter two crashes since the last activity needs information stored in the application class.
Activity A >> Activity B (needs info from Application class) >> Activity C
Crash occurs on C >> Application tries to open Activity B >> Crash occurs on B because it needs info from the Application class (this has been reset)
I want to avoid this, so I was hoping that there is someway I can restart the whole application after a crash instead of the activity.
This is one possible solution of many but I'll put it here as an option:
You could use startActivityForResult() and when you handle the error in Activity C, finish() it with a result code that you recognize as a crash and handle things appropriately in the onActivityResult() of Activity B.
Getting a Result from an Activity
The nicest solution is to handle the case in which you do not have the necessary information at any activity (in your case Activity B).
You should check at the onCreate method whether you have the information or not, and act in consecuence:
Finishing the activity to go back to your activity A
Launching another activity
Asking the user for feedback
Any other action you think fits best
There may be more than one reason explaining why you don't have that information (as other answers point out), so in my opinion the best option is to handle the case.
Untested theory, just spitballing.
Could you attach yourself as a default exception handler, and start calling finish() on the open activities? If you can finish all your activities, wouldn't that effectively shut down the app, and reopening it would be as if it were getting launched fresh?
You shouldn't keep any state in the Application object. Keep it in the Bundle you receive in the onCreate(). Eventually use onSaveInstanceState / onRestoreInstanceState to save/restore state.

When are ALL the cases when the onSaveInstanceState() method called?

All the sources I read have all mentioned couple of cases and concluded with "a few other cases". What are ALL the cases when the onSaveInstanceState method called in a View/Activity?
onSaveInstanceState() will be called by default for a view if it has an id.
google said: "The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id".
More info here.
Whenever there is as soft kill of the activity. I.e when the orientation changes or when the process is killed by android due to low memory.
It's not called when the user knowingly just navigates away from the activity.
Refer to this link: https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/saving-instance-state
The doc says
This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state.
Also be aware that onSaveInstanceState can be called on a fragment directly after onCreate (onCreateView, onActivityCreated, onStart, and onResume will NOT be called), if the fragment is attached to an activity but not shown, then destroyed. Thus you need to be sure that everything you reference in onSaveInstanceState is initialized in onCreate, otherwise you risk a NullPointerException.
onSaveInstanceState() is called when there is an orientation change
or user presses home button.
If there is an another activity in front of an
activity and the OS kills the hidden activity in order to free
memory(or when memory is needed elsewhere), then onSaveInstanceState() is called so activity can save its state information which is restored using onRestoreInstanceState() when user start that activity next time .
Default views of Android save their state via a call to
View.onSaveInstanceState which is restored by the default implementation of onRestoreInstanceState
As per doc
If the user interacts with an activity and presses the Back button or
if the finish() method of an activity is called, the activity is
removed from the current activity stack and recycled. In this case
there is no instance state to save and the onSaveInstanceState()
method is not called.
If the user interacts with an activity and presses the Home button,
the activity instance state must be saved. The onSaveInstanceState()
method is called. If the user restarts the application it will resume
or restart the last running activity. If it restarts the activity it
provides the bundle with the save data to the onRestoreInstanceState()
and onCreate() methods.
If you override onSaveInstanceState() and onRestoreInstanceState() you
should call the super implementation of it, because the default views
of Android store their data via a call to View.onSaveInstanceState
from the onSaveInstanceState() method of the activity. For example
EditText stores its content via the default call of this method.
This method did not call when user presses "return" button,this is one of that case..
onSaveInstanceState is called when ever activity is out of veiw.. like when u press home key, onSaveInstanceState is called.
From here: the answer is onSaveInstanceState() gets called regardless of whether or not your app process is killed. So in all of these scenarios, onSaveInstanceState() is called:
Normal background scenario
Your activity goes into the background and onSaveInstanceState() is called
You do some other things
Your user navigates back to your activity
Process kill background scenario
Your activity goes into the background and onSaveInstanceState() is called
You do some other things and during this time the system starts running low on resources and closes your app’s process
Your user navigates back to the activity
onRestoreInstanceState() and onCreate() (with the saved instance state bundle) are called
Configuration change scenario
A configuration change occurs and onSaveInstanceState() is called
onRestoreInstanceState() and onCreate() (with the saved instance state bundle) are called
The difference is whether onCreate()/onRestoreInstanceState() are called. In the process kill and configuration scenarios they are called. In the normal scenario, there is no need to recreate the activity and neither are called.
Note that onSaveInstanceState() is called when your activity goes into the background and NOT when the app process is about to be killed. This is because in the scenario your app process gets killed, the system is pretty resource constrained as is and it would NOT be a good time to spend cycles storing key/value pairs in RAM.

android thread crashes when screen orientation changes

I am making an android app, which needs to download a text from a url and show it on a alertdialog.
I created a new thread. The thread reads a file on the web, a progressdialog appears before the thread starts, the thread packages the file content from the web on bundle , and passes it to a handler, the handler stops the progress, and shows the text from the bundle on a alertdialog. Well this works pretty good, but when the screen orientation changes when the progressdialog is shown and the thread is running, the app crashes. Any ideas on how to fix this thing?
Any help will be appreciated. :)
When the orientation changes, normally the OS will shut down your activity completely and restart it. That will mess up your download thread. One solution that might work is to save the Thread object as non-configuration data. You'll need to override onRetainNonConfigurationInstance() in your activity. However: do not do this if your Thread object has any references to any view- or activity-related object. That will cause a huge memory leak and will make your users very unhappy very quickly.
See the guide topic Handling Runtime Changes for details on using onRetainNonConfigurationInstance() and also an alternative approach. See the article Avoiding Memory Leaks on ... well, just that.
Add activity to menifest file as following -
<activity
android:name=".MyActivity" //Replace MyActivity with Your activity
android:configChanges="orientation|screenSize|screenLayout">
</activity>
This usually happens because your Activity actually gets destroyed and recreated on orientation changes.
Your options are:
Embrace the destruction, and use an AsyncTask instead of a Thread to fetch your data. You cancel() the task in your onDestroy() method.
Also use AsyncTask and cancel() it in your onDestroy() method. Additionally, handle configuration changes such as in the answers to this question.
KSubedi... Assumptions can be dangerous. Step by step testing to eliminate the exception may reveal that it is the running progress dialog that is causing the exception. The cure is:
protected void onPause() {
super.onPause();
//if (asynch != null) {asynch.cancel(true);}
if (progress != null){progress.cancel();}
}
JAL

Categories