0

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.

Community
  • 1
  • 1
NoHarmDan
  • 492
  • 5
  • 16
  • Your question would be more readable with the use of some paragraphs. From where are you calling your `showFragment` method? The docs state that you cannot create/commit a transaction AFTER `Activity.onSaveInstanceState` is called (unless another `Activity.onResume/onStart` has been called), which I'm guessing is the problem. If using `commitAllowingStateLoss()` instead of `commit()` gets rid of the exception, then I'm probably right about my guess. – Reed Feb 20 '15 at 18:16
  • 1
    I guess I should have said that I have tried that... I believe you misunderstood my problem, because these issues are unrelated. The exception is caused by a bug in the fragment (which is being loaded from an external file, therefore can contain errors). What I need to do is catch the exception (in the fragments code, not in the commit) that happens when the commit is actually executed, and then not execute it. I am starting to think that that is impossible, since the transaction gets queued up anyway and catching the exception can only postpone its execution. – NoHarmDan Feb 21 '15 at 11:19
  • Yeah, I misunderstood. You could try using your own `UncaughtExceptionHandler` (see [this SO post](http://stackoverflow.com/a/19968400/802469) ). I'm not sure if it'll work as you need it to, but it's all I could think of. – Reed Feb 21 '15 at 16:45
  • 1
    Oh, thanks a lot, never thought of that. I'll give it a try. Although it's a bit of a stretch and probably not a "proper" way to do it, it might be the only possible one. :) I'll try and return with info about where it got me. – NoHarmDan Feb 21 '15 at 20:44

1 Answers1

1

The final conclusion is that this is impossible at the moment. As said in the edit of my question:

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.

So, there's no point in trying to achieve this.

NoHarmDan
  • 492
  • 5
  • 16