1

I'm adding Crashlytics into an app and I ran a couple tests. When I throw an exception within an async task the report didn't appear in the console. Is this a known issue or should it be coming through?

AsyncTask.execute(new Runnable()) {
    @Override public void run() {
        throw new RuntimeException("THIS IS A TEST");
    }
 }

I know that Crashlytics is set up correctly because an exception thrown from the same function but outside the AsyncTask wrapper shows up just fine. Can anyone else share their experience with crashes that occur asynchronously?

UPDATE I ran more tests and I found that part of my issue was that I had a handler for uncaught exceptions. I had this in place so testers would get a dialog box and they could just tap OK to get a logcat attached to an email. (Thanks to need-to-handle-uncaught-exception-and-send-log-file) I tried a number of things and I in my case I just need to pick one or the other, the uncaught exception handler or the crashlytics. It works for me this way since I only really want the crashlytics in place for the production+release variant. I tried including Crashlytics.logException(e) in the body of the exception handler but that didn't work. Possibly because the function calls System.exit(1) right after. Anyway... this is what I have now that does the job.

To use a custom application class, update the manifest

    <application
    android:name=".util.App"

In the App class I either set up the uncaught exception handler or the crashlytics.

public class App extends Application {
    public void onCreate() {
            super.onCreate();

            Constants.IS_DEV = BuildConfig.FLAVOR.equals("dev");

            if (Constants.IS_DEV || BuildConfig.DEBUG) {
                    setupUncaughtExceptionHandler();
            } else {
                    Fabric.with(this, new Crashlytics());
            }
            [SNIP]
    }

    private void setupUncaughtExceptionHandler() {

            // Setup handler for uncaught exceptions.
            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread thread, Throwable e) {
                            handleUncaughtException(thread, e);
                    }
            });

    }

    public void handleUncaughtException(Thread thread, Throwable e) {

            // Crashlytics.logException(e); did not work here

            // create intent to launch new instance and show 'send_log' dialog
            Intent intent = new Intent();
            intent.setAction(BuildConfig.APPLICATION_ID + ".SEND_LOG");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            System.exit(1); // kill this instance
    }

    [SNIP]
}

My tests were just functions I grabbed in the settings page. They're just text items with onClick method set to 'onClick' (how original :)

public class SettingsActivity extends DataSourcedActivity {

    [SNIP]

    public void onClick(View view) {
            if (view == findViewById(R.id.txtSettingsRemove)) {
                    launchRemoveItemsPage();
            } else if (view == findViewById(R.id.txtSettingsRestorePurch)) {
                    launchRestorePurchases();
            } else if (view == findViewById(R.id.txtContactSupport)) {
                    launchContactSupport();
            } else if (view == findViewById(R.id.txtGetUpdates)) {
                    launchGetUpdates();
            } else {
                    throw new DevException(Constants.UNKNOWN_SETTINGS_OPTION);
            }
    }

    private void launchRemoveCollectionsPage() {
            AsyncTask.execute(new Runnable()) {
                    @Override
                    public void run() {
                            throw new RuntimeException("THIS IS AN ASYNCHRONOUS TEST");
                    }
            }
            [SNIPPED ORIGINAL CONTENTS OF FUNCTION]
    }

    private void launchRestorePurchases() {
            throw new RuntimeException("THIS IS A TEST");
            [SNIPPED ORIGINAL CONTENTS OF FUNCTION]
    }

    [SNIP]
}

When I tried to use both the Crashlytics and the uncaughtException handler I got different results depending on which I set up first. If I setup Crashlytics first and then my uncaughtExceptionHandler then it appeared that mine overrode Crashlytics, no crash report made it to the console. If I setup my uncaughtExceptionHandler first then I do get the crash report on the console.

So I'm leaving this here just in case it might be helpful to others who run into this.

Mike

Mike
  • 788
  • 10
  • 27
  • 1
    Does this exception crash the app with the infamous "Unfortunately MyApp has stopped" message? Or does it only stop the AsyncTask's thread without affecting the main thread? – Code-Apprentice Dec 01 '17 at 17:43
  • In my controlled test I used two functions from my 'settings' page. Each of them crashed the app in the same manner. In the first case, the one without the AsyncTask, the crash appeared on the console in real-time, I just refreshed the page. In the second test it didn't show, and still hasn't. – Mike Dec 01 '17 at 18:41

1 Answers1

3

The crash comes on the next subsequent launch. The crash gets logged locally, then the next time you launch the 'same build or app' it sends the report up on startup.

Please ensure that you are starting crashlytics properly, and make sure you are launching the app a second time from the same app on your device to ensure it gets sent. Hitting play again and again from your debugger may have undesired results of sending the issue to the dashboard.

Also, in debug you may find slightly delayed posting, I've seen it take as much as 5 minutes before.

Sam
  • 5,342
  • 1
  • 23
  • 39
  • I'm using my Application subclass in the onCreate method and using the code right out of the documentation `Fabric.with(this, new Crashlytics());` At this point I'm just getting started so I'm only focused on the crash reporting. – Mike Dec 01 '17 at 18:48
  • That is good, and you confirmed your ApplicationName is in the Application tag of your manifest and the start method is called? Are you saying if you hit a crash, and then from your phone, launch the app again it does not show up? Keep in mind if you have the first thing in your app "throw exception" you may need to put it on a button crash to allow some actual time to process. – Sam Dec 01 '17 at 19:11
  • I don't see the 'start' method mentioned in the documentation for installing Crashlytics (https://fabric.io/kits/android/crashlytics/install). It's just `Fabric.with(this, new Crashlytics());` and run. My test involves two buttons from my settings page. One uses an AsyncTask.exectute(runnable) and the other one just throws the exception right away. I have done some more tests and I'm going to post an update. – Mike Dec 01 '17 at 19:33
  • you don't have to call Start any longer. ok I will wait for your update. – Sam Dec 01 '17 at 19:42