Android: error adding frament to the activity - android

There are some peculiarities on android that i hate like a hell...
The issues around isFinishing() of activity are the worst.
I do understand some actions are not allowed after or during this process, but the only way we have to check it is by this method, and somethimes it isn't effective let me show a very simple example and please guide me in how to solve it with the best practices:
I want to add a fragment to my screen
if(!this.isFinishing() && getSupportFragmentManager().findFragmentByTag(VerifyIdentityDialog.CHALLENGE_DIALOG_TAG) == null)
try {
new VerifyIdentityDialog((ChallengeRequiredException) e, new DefaultVerifyIdentityListener())
.show(getSupportFragmentManager(), VerifyIdentityDialog.CHALLENGE_DIALOG_TAG);
} catch (Exception e1) {
Crashlytics.logException(e1);
}
This code is running only on MainThread it explicitly checks if the activity is finishing before try but still i get around 2% of users running into exception on it...
The exception is:
java.lang.IllegalStateException
Can not perform this action after onSaveInstanceState
[Avoid pasting long stack trace since it is a default android exception and the related code is mentioned above]
1- Before i added !this.isFinishing() in the if, the exception was way more frequent, but still didn't solve it 100%
2- according to Crashlytics 97% are on background when it hapens, so I THINK the code starts, the user goes to background then it simple crashes
the question is...
how is the proper way to solve it... i hate catching exception for predictable situations

You can directly check whether the FragmentManager has saved its state via isStateSaved() - you should only show() your dialog if the state is not saved.

Related

How does app know if it started from a crash

Whenever I start the app I want to know if the app recovered from a crash. Can I store it in a flag ?
Do the crash and regular app exit scenario go through the same steps(lifecycle) in android ?
You can override your crash exception by using Thread.setDefaultUncaughtExceptionHandler. But do not forget, If you would not close your application it will freeze the screen by OS.
Example code :
//variable that inside the application class
private Thread.UncaughtExceptionHandler defaultUEH;
public void onCreate(){
super.onCreate();
defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
#Override
public void uncaughtException(Thread t, Throwable e) {
handleUncaughtException(t,e);
defaultUEH.uncaughtException(thread,e);
}
});
}
private void handleUncaughtException(Thread thread,Throwable e){
//do whatever you like!
}
NOTE : There is no way to understand how is your program is opened
You don't get this information at all from the Android SDK. There are two options you could try, first is would be to have extensive logging/tracking of the apps life-cycle. In all of your activities keep track of when you activities are started, resumed, paused, stopped, and destroyed. (Also handle special usecase of when the device is rotated and the activity will experience a tear-down and restart). From here you will have information of when an activity has been stopped and you check the last state in the onCreate, onStart, or onResume of you activities to make sure that you're expected life-cycles where hit. If not, then you more than likely experienced a crash. Also note, on older version of Android certain teardown life-cycle callbacks weren't guaranteed to be called.
Second option would be to try using Thread.setDefaultUncaughtExceptionHandler. I have never personally used it but it may help in the usecase where an uncaught exception occurs. You could log such an event and check that flag once, the app is resumed. I am not sure of all of the side effects of using this mechanism such as, will this override the default uncaught exception behavior and remove the default stack trace that gets printed out, which would be very very very bad.
There is no way for the app to know whether it started from a crash; this is indistinguishable from starting the application for the first time after booting. In both cases you will see the onCreate lifecycle event for your activity.
If your application crashes, it stops processing lifecycle events. So no, lifecycle events will not be processed in the same way.
If you want to know whether your application is crashing, perhaps a better approach is to directly record when the application crashes. There are tools like Errbit that help record this when the application is running on general users' devices.
Try to add Exception handling to the code to whatever is causing a crash.
try{
//code causing the crash
} catch (Exception e){
//code to set flags whenever an event causing crash occurs.
}

Fragments: IllegalStateException Can not perform this action after onSaveInstanceState

I am sending an HTTP request to some server(in a background thread) inside onCreateView() method within my fragment class.
When the request received i check some stuff and according to that i add a new fragment(through fragment transaction in the UI thread).
I use the support library
But, for example, if the user press the android home button, while the request hasn't received yet, the fragment is going to pause or stop state and then the request received and of course the exception is thrown(just after trying to commit).
I searched the web and found some very good articles and answers which are relevant to this issue and all the things related to the 'state loss' after onSaveInstanceState() has been called, etc...
For example i read this excellent article of Alex Lockwood: http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
and also those stackoverflow questions/answers: getting exception "IllegalStateException: Can not perform this action after onSaveInstanceState"
and: "Can not perform this action after onSaveInstanceState" - why am I getting this exception from my activity's onResume method? and more.
But i couldn't came to a conclusion of what to do in my case.
The only thing that came to mind is to use commitAllowingStateLoss() instead of commit() but this fills hacky and not correct as some of the answers that i read conclude about it.
Also there was a suggestion to commit the transaction in onCreate() because it safe, but of course it can't work in my situation, all other suggestions doesn't work for me as well.
Maybe i can use some boolean flag to check if i can't make a transaction and then wait for the fragment to resume and if the flag is true then do the transaction.
This fills to much work and also presents the problem in which i need to know if the transaction can be done(don't even know how to check it).

Activity Idle Timeout for ActivityRecord

So I have a strange problem, and I'm not entirely sure what all information I should provide, but I'll do my best -- just let me know if I need to add more info. I'm having an issue that when I finish my Activity and return to the previous Activity (or launch it with a new Intent -- the problem seems to be centered on finishing the Activity) the UI performance drops drastically for about six or seven seconds, then returns to normal.
From LogCat, this warning appears consistently:
07-11 22:09:42.594: W/ActivityManager(292): Launch timeout has expired, giving up wake lock!
07-11 22:09:42.601: W/ActivityManager(292): Activity idle timeout for ActivityRecord{42bf6e00 com.kcoppock.sudokubeta/com.kcoppock.sudoku.SudokuBoardActivity}
As soon as the activity times out, UI performance returns to normal. Until that point it is very sluggish. I have no code that I am aware of that could be blocking the main thread, and I've even gone so far as to comment out my entire onPause() method to see if it makes any difference, and it does not.
The Activity does not spawn any background threads, does not perform any network activity, the only disk access it has is some accessing of SharedPreferences. The previous questions I've been able to locate are about idle timeouts for HistoryRecord, not ActivityRecord.
Any ideas what would cause this? Or how I could go about determining what is blocking the UI thread, if that is what is happening?
EDIT : Okay, just tried commenting out everything except super.onCreate() and setContentView() -- the problem still persists. It doesn't occur with any other Activities but this one, but there's NOTHING TO this one. :/
Oh geez. One of those things that's pretty hard to diagnose outside of trial and error, but I've figured it out. For reference, should anyone else have this problem, it came down to a custom view in my layout. I had added a ViewTreeObserver.OnGlobalLayoutListener() to do some layout modifications after the layout pass, but within that listener I modified the layout and thus caused another layout, essentially creating an infinite loop (but somehow not causing an ANR). My solution was like so:
private class BoardLayoutListener implements OnGlobalLayoutListener {
#Override
public void onGlobalLayout() {
//...do stuff here
//REMOVE this listener so that you don't repeat this forever
ViewTreeObserver obs = SudokuBoard.this.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
}
}
This solution is quite ironic, considering my second highest rated answer on StackOverflow specifically deals with this. :P
sigh
I've had the same issue today but as it turned out to have a different cause and solution I decided to add the information here just in case it might help someone else.
In my case problem was caused because I had the following line inside my onActivityResult() method:
android.os.Debug.waitForDebugger();
I Just deleted the line and the problem was gone.
This line is usually used to synchronize the debugger with the OS threads but I just figured it shouldn't be used anywhere. Oddly the problem would not appear until I had my phone disconnected from the desktop.
Regards

How to show a dialog for an exception while halting the rest of the program flow?

I have thought out an IMHO neat way of handling checked Exceptions, like so:
protected void handleException(Throwable e, int messageResourceId, ExceptionReaction reaction) {...}
which would be part of the app's BaseActivity (thus usable in all Activities).
Within this method I intend to show a dialog with the given message string and an OK button, and afterwards do something to react individually to the Exception (restart the activity, log the user out, reset database,...).
However, the dialog is started on the UI thread non-blockingly, and the Activities having called handleException(...) would just continue execution while the dialog is shown - which sucks, because something most probably has gone very wrong and e.g. an activity-restart might be needed.
Note that the UI thread can't be put to sleep or wait, since then the OK button in the dialog would not work at all.
Has anybody got an idea how to achieve this?
Has anybody got an idea how to achieve this?
Put your "do something to react individually to the Exception" in the dialog close-button handler, such as via a final Runnable.
Have you tried UncaughtExceptionHandler?
Refer this doc Thread.UncaughtExceptionHandler
Implement this interface and do the handling stuff in the callback uncaughtException(Thread thread, Throwable ex)

Undefined result when opening managed dialog in AsyncTask when in background

I have a problem that causes me some problems when a user (or another app, like the phone-application) pushes my application to the background.
My application does following:
A User can enter some information that is supposed to be pushed to a server.
When the user clicks "Send" i open a managed ProgressDialog and start an AsyncTask that performs the server communication.
When server communication is complete the AsyncTask reports back to my Activity where i perform a dismissDialog().
Directly after dismissDialog(), I will show another managed dialog using showDialog() that will inform the user about whether the submission was ok or if it failed.
This all works perfectly without any issues; however, when a call happens to come while the AsyncTask is running I get (seemingly random) one of these results:
The activity holding the managed dialog is dismissed completely and the previous view from the stack is presented when I come back.
The activity holding the managed dialog is still on screen, but it is grayed out without showing a dialog. The only way to fix this is to rotate the phone at which point it shows the "Submission sent"-dialog exactly the way it should and everything is ok after that.
All this happens without any warning messages so I get absolutely no clues as to why Android is behaving this way.
I know a way around this and that is to cancel the AsyncTask (so no dialogs are shown at the end). However, in this very use-case the requirements are that the app has to try to complete the server transaction so that there is as little confusion as possible (i.e. the user wondering if it was really sent or not).
Has anybody else had this issue and knows a way around?
I see recommendations to hold a reference to the asynch task in onRetainNonConfigurationInstance
What to do with AsyncTask in onPause()?
Or implement a bus:
https://github.com/commonsguy/cwac-bus/tree
EDIT: The complexity of your challenge is two fold:
1) saving and restoring state of your app on a kill such as when there is an incoming phone call
https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/saving-instance-state
2) somehow continuing the asyncTask on kill instead of canceling it onPause
https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/asynch
Both of these are significant challenges alone, and trying to fix both at the same time would give me a headache. In fact, I am getting a headache just thinking on it :) One clue is that you say the dialog returns on orientation change. This MAY be due to the fact that using the standard architecture for dialogs, the OS handles saving and restoring the state of dialogs for you on orientation change.
[EDIT] See CommonsWare
#Override
public Object onRetainNonConfigurationInstance() {
task.detach();
return(task);
}
and
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bar=(ProgressBar)findViewById(R.id.progress);
task=(RotationAwareTask)getLastNonConfigurationInstance();
if (task==null) {
task=new RotationAwareTask(this);
task.execute();
}
else {
task.attach(this);
updateProgress(task.getProgress());
if (task.getProgress()>=100) {
markAsDone();
}
}
}
where task is an instance of
static class RotationAwareTask extends AsyncTask<Void, Void, Void> {
I see no reason why this would not work for all types of soft kills, but on a hard kill, well, you get killed. Dead is dead :)
Without looking at your code it is slightly difficult to say what the problem is. However, here is something you could use to help get around the problem. You can override the onPause() method of your Activity.
This is taken directly from the Android Acitivy javadoc:
onPause() is where you deal with the user leaving your activity. Most importantly, any changes made by the user should at this point be committed (usually to the ContentProvider holding the data)

Categories

Resources