I have a almost-completely-working modular (on-the-fly external fragment loading) application on Android.
The only thing left is handling exceptions and errors. One of the possibilities that can occur is an error in the module's (fragment's) code, such as calling a non-existant method or an average null pointer (which can and does happen).
The fragments basic methods appear to be called when the fragmentTransaction
is commited (which is NOT when fragmentTransaction.commit()
is called), which makes the exceptions quite hard to catch. I can "force" catch the exception by calling getSupportFragmentManager().executePendingTransactions()
, as illustrated.
The problem is that the commit will still happen at some point - for instance pausing the application makes it save its state and therefore commit all pending transactions, which ends in an exception (meaning the exception caused by the error in the fragments code, not an IllegalStateException
) even though the commit has been postponed by the catch block. The following method causes this behaviour.
private void showFragment(String name) {
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.linear_main, fragmentMap.get(name));
try {
fragmentTransaction.commit();
getSupportFragmentManager().executePendingTransactions();
} catch (Exception e) {
// Do nothing :)
}
}
I have tried various ways of countermeasures (all ending in different exceptions at different points in time, but none working properly), settling on one which seems the most rational, although still doesn't work at all. :D That is the code below, which actually shows a little different behaviour - it immidiately throws a java.lang.IllegalStateException: Recursive entry to executePendingTransactions
which I suppose has something to do with a collision of the commit and trying to pop the stack back. (Yes, I do not understand the FragmentManager
behaviour quite enough...)
Searching for this error brings up solutions to fragment inside fragment problems, which are completely unrelated to my problem.
private void showFragment(String name) {
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.linear_main, fragmentMap.get(name));
fragmentTransaction.addToBackStack(null);
try {
fragmentTransaction.commit();
getSupportFragmentManager().executePendingTransactions();
} catch (Exception e) {
getSupportFragmentManager().popBackStackImmediate();
fragmentMap.remove(name);
Log.e("showFragments", name + " removed", e);
}
}
So, basically I need to check whether the fragment's onCreate
(and onCreateView
and such...) doesn't cause an exception before actually making the fragmentTransaction
. It would seem that playing around with try-catches on the commit cannot do the trick. I just need to stop the fragment from being rendered, rather than having the whole app crash. Any out of the box ideas?
Thanks. :)
EDIT:
I realised that since any error of the mentioned kind can happen anywhere later on during runtime of the fragment, it's pointless trying to catch the errors when the fragment is added. (Oh dumb me...)
Setting the default uncaught exception handler (thanks to Jakar for pointing me to this post) can help with informing the user that the error was caused by a plugin, but the application still must crash since it's practically impossible to tell which plugin caused the exception and removing it or whatever (removing would be impossible if the exception occured during initialization, but it should be possible if the exception occured later on).
This therefore renders my question to be of no importance, although it would be interesting to be able to do what I described.