Android Tutorial Auto restart an Android Application after a Crash

Discussion in 'Tutorials & Examples' started by OliverA, Mar 18, 2019.

  1. OliverA

    OliverA Well-Known Member Licensed User

    Sources used:
    Main sources:
    https://medium.com/@ssaurel/how-to-...r-a-crash-or-a-force-close-error-1a361677c0ce
    https://www.b4x.com/android/forum/t...estartatexact-not-accurate.65117/#post-412286
    Additional:
    https://stackoverflow.com/a/2903866
    https://mobikul.com/auto-restart-application-crashforce-close-android/

    Known limitations:
    This has only been tested with a single activity (Main) application. More explanation to follow below.

    Part 1:
    The first part involves installing a default uncaught exception handler. The solution requires some inline Java and the JavaObject library.

    Add the following inline Java to your Main class:
    Code:
    #if Java
    //Sources:
    //https://medium.com/@ssaurel/how-to-auto-restart-an-android-application-after-a-crash-or-a-force-close-error-1a361677c0ce
    //https://stackoverflow.com/a/2903866
    //https://mobikul.com/auto-restart-application-crashforce-close-android/

    public void setDefaultUncaughtExceptionHandler() {
       
       Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));
    }

    import android.app.Activity;

    public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {

      private Activity activity;

      public MyExceptionHandler(Activity a) {
        activity = a;
      }

      @Override
      public void uncaughtException(Thread thread, Throwable ex) {
        activity.finish();
        System.exit(2);
      }
    }
    #End if
    Declare the following JavaObject in Globals (adjust name if necessary to avoid conflicts):
    Code:
    Private nativeMe As JavaObject
    And add the following code in the Activity_Create sub:
    Code:
    nativeMe.InitializeContext
    nativeMe.RunMethod(
    "setDefaultUncaughtExceptionHandler"Null)
    That finishes installing your own default uncaught exception handler. With this in place, when you Main class crashes, the application will exit without requesting the user to restart the application. This is key in allowing the application to restart without user intervention. For applications that are set as the Home screen, this would suffice, allowing Android to restart it without user intervention.

    Part 2:
    First, a sub that allows us to schedule the starting of an Activity. It is a modified version of @Erel's
    SetExactAndAllowWhileIdle sub he posted (the modification allowing it to start an Activity instead of a Service):
    Code:
    'Based on: https://www.b4x.com/android/forum/threads/now-android-6-servicestartatexact-not-accurate.65117/#post-412286
    'Time: The time that the Activity should start - in ticks
    'ActivityName: The name of the Activity that should be started
    'Message: A message that will be passed along in the intent to start the Activity (via Extras)
    Sub ScheduleRestartCrashedActivity (Time As Long, ActivityName As String, message As String)

       
    Dim in As Intent
       
    in.Initialize("""")
       
    in.SetComponent(Application.PackageName & "/." &  ActivityName.ToLowerCase)
       
    in.PutExtra("Crash", message)
       
    in.Flags = Bit.Or(FLAG_ACTIVITY_CLEAR_TASK, Bit.Or(FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_NEW_TASK))
       
       
    Dim jin As JavaObject = in
       jin.RunMethod(
    "setAction"Array(Null))
       
       
    Dim ctxt As JavaObject
       ctxt.InitializeContext
       
    Dim am As JavaObject = ctxt.RunMethod("getSystemService"Array("alarm"))
       
    Dim pi As JavaObject
       pi = pi.InitializeStatic(
    "android.app.PendingIntent").RunMethod("getActivity"Array(ctxt, 0in, FLAG_ONE_SHOT))
       
       
    Dim p As Phone
       
    If p.SdkVersion < 20 Then
           am.RunMethod(
    "set"Array(ALM_RTC, Time, pi))
       
    Else If p.SdkVersion < 23 Then
           am.RunMethod(
    "setExact"Array(ALM_RTC, Time, pi))
       
    Else
           am.RunMethod(
    "setExactAndAllowWhileIdle"Array(ALM_RTC, Time, pi))
       
    End If
       
    End Sub
    This sub should be placed in the Starter service. You will need to also declare the following in Process_Globals:
    Code:
    Private const FLAG_ACTIVITY_CLEAR_TOP As Int = 0x04000000
    Private const FLAG_ACTIVITY_CLEAR_TASK As Int = 0x00008000
    Private const FLAG_ACTIVITY_NEW_TASK As Int = 0x10000000
    Private const FLAG_ONE_SHOT As Int = 0x40000000
       
    Private const ALM_RTC As Int = 0x00000001
    Private const ALM_RTC_WAKEUP As Int = 0x00000000
    The sub needs to be called from the Application_Error method. For example:
    Code:
    Sub Application_Error (Error As Exception, StackTrace As StringAs Boolean
       ScheduleRestartCrashedActivity(
    DateTime.Now + 300"Main", Error)
       
    Return True
    End Sub
    With all these pieces in place, if your Main activity crashes, it will be scheduled to restart in 300 milliseconds (the + 300). Additionally, you can check Main's starting intent to determine if your app was restarted as a crash. For example, the following code placed in Activity_Create will produce a log after crash:
    Code:
    Dim i As Intent
    i = 
    Activity.GetStartingIntent
    If i.HasExtra("Crash"Then
        
    Log("After crash: " & i.GetExtra("Crash"))
    End If
    Notes:
    1) Each Activity may need to register their own default uncaught exception handler. If so, it's left up to the reader to determine which Activity needs to be restarted via ScheduleRestartCrashedActivity.
    2) I do not know what happens when a Service crashes.
    3) The ScheduleRestartCrashedActivity does not require the Starter Service. It does require that a Service handles the Application_Error event.
    4) I'm currently using ALM_RTC to schedule the intents. This will not wake the phone. If that is a requirement, replace with ALM_RTC_WAKEUP.
    5) Could not decide between a Snippet post or Tutorial post. This seemed a little to long for a Snippet.
     
  2. Erel

    Erel Administrator Staff Member Licensed User

    Check Application_Error in the starter service. You can probably implement something similar based on Application_Error.
     
  3. OliverA

    OliverA Well-Known Member Licensed User

    The key here seems to be the System.Exit() call. With the above code in place, if an exception occurs that ends the Activity, Application_Error is called first and then the default exception handler. I guess the question is, does anything else happen after Application_Error is called that needs to happen? If so, I'll need to do this to properly close out the app. If, on the other hand, nothing special happens after Application_Error, I probably can call System.Exit (via inline java) in the Application_Error event and stop processing right there and then.
     
  4. Erel

    Erel Administrator Staff Member Licensed User

    ApplicationExit = System.Exit.

    You can return True to let the default handler do its part. This will cause the process to end.
     
  5. sorex

    sorex Expert Licensed User

    I confirm that Erel's method does the job aswell.

    I'm storing the errors in a map and send them one by one to a webserver that mails them to me and if that was successful I remove the error from the map.

    This way nothing gets lost and I was also able to track down issues that never happend at my end.
    (for example an error in the wifi lib happening when people were walking around between access points and lost connection and caused a null pointer exeption during a read out of some parameters)
     
  6. OliverA

    OliverA Well-Known Member Licensed User

    Yes, but is the user asked to restart the application? That question to the user blocks auto-restarting. I'm also using Application_Error, but I'm calling System.Exit(a-non-zero-value) from a separate default uncaught exception handler which suppresses the restart question (the application/service just stops). The intent set in Application_Error restarts the application at a future time ( Application_Error is executed before the custom default uncaught exception handler). I could (still not tested) call System.Exit in Application_Error, but that would (I think) exit the application without processing whatever B4A does right after calling the Application_Error event. In other words is Application_Error set up like this (pseudo code follows):
    Code:
    some code
    call Application_Error 
    event
    some more code 
    to finish application
    or
    Code:
    some code
    call Application_Error 
    event
    //No other code follows the 
    event. The event is the last code the application processes.
    //I can just go ahead 
    and make System.Exit my last call in Application_Error
     
  7. sorex

    sorex Expert Licensed User

    in my case nothing is asked to the user. the app just continues to work.

    I guess the first code block is valid in my case with the exeption that the app doesn't get finished.
     
  8. OliverA

    OliverA Well-Known Member Licensed User

    If the app just continuous, then you are returning False from Application_Error (my assumption is that you are not using my code here to restart your app). The issue with that could be that your app could be in a precarious state, since you did have an uncaught exception. It is up to the programmer to determine if an exception was severe enough to exit an application (therefore the option of true and false as return values for Application_Error).
     
  9. sorex

    sorex Expert Licensed User

    well, it's a special case...

    it's sound monitoring children with disabilities during nights so the 'sleeping guard' needs to have working apps or he/she needs to walk through the buildings all night to validate that nothing is wrong.

    but indeed for some apps a restart or partial reload might be better.
     
    OliverA likes this.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice