In my application, i want to set the uncaught exception handler so that i can do stuff in the event that of an unforseen crash. (i want to do stuff like close out sockets, clear notification...etc.)
Thread.currentThread().setDefaultUncaughtExceptionHandler(sDefaultThreadHandler);
where
private static UncaughtExceptionHandler sDefaultThreadHandler = new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
// i want ACRA to log here, then clear notifications, close out connections, cancel asynctasks...etc.
// DO NOT REMOVE or else your app will hang when there is a crash.
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
}
};
the problem is, i want ACRA to also report before the process exits. how do i accomplish this?
Oh wait, nvm. i found out that ACRA uses the default exception handler (according to https://github.com/ACRA/acra/blob/master/src/main/java/org/acra/ErrorReporter.java#L201), so that means that if your own thread has a thread exception handler, that will be used first.
Thread.currentThread().setUncaughtExceptionHandler(mYourOwnThreadHandler);
and if you really need to use ACRA, then inside the uncaughtException() method that you override, just delegate it upwards by calling Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, ex);
Related
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.
}
I have a class which extends Application. In its onCreate() I have:
Thread.currentThread().setUncaughtExceptionHandler(
new UncaughtExceptionHandler()
{
#Override
public void uncaughtException(Thread thread, Throwable ex)
{
System.exit(0);
}
});
expecting my app to go off forever. But after System.exit(0) is called, android restarts my application as if I've launched it myself. Why?
By the way, do you know any way to show an AlertDialog notifying the user of the uncaught exception?
You can not use System.exit() in Android, it causes undesired behavior as you have found. If you must terminate an activity, use finish() instead and let Android clean it up.
My app is composed of a single Activity. In this activity, I'm creating multiple HandlerThreads which run in a loop to do socket blocking operations.
Currently I post a quit message to everyone of these HandlerThreads during my Activity.onDestroy().
Sometimes, when I open my app, close it and relaunch it, it crashes (many time due to posting a message to a handler thread which is not running).
My question is: What is the right way to close HandlerThread when I close my app? (Note that those threads might be blocking on a socket operation).
EDIT: More information:
I have a pool of Handler Threads which is initiated in onCreate (No problem when I'm launching my app at the first time).
Each handler runnable loop is wrapped with an
if (shouldRun) {
//body
}
else {
close();
}
statement.
the close method remove all pending messages and runnables and post a message to the handler that will cause him to call its looper.quit().
This way, if the current handler thread is blocked by IO operation, only once it will finish it he will quit().
Yes, it would be a good idea to close it. Also make sure to remove your callbacks.
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
handler.getLooper().quit();
}
/**
* Ask the currently running looper to quit. If the thread has not
* been started or has finished (that is if {#link #getLooper} returns
* null), then false is returned. Otherwise the looper is asked to
* quit and true is returned.
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
Above is the 'quit' method of the source code of HandlerThread.java, just invoke it directly.
Why should called quit? Below is 'run' method of the source code of HandlerThread.java.
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();//always loop except for a Message with null target
mTid = -1;
}
The answer is 'loop is a 'while(true)' method,It will return until receive a Message with null target.
You must have some inconsistency there, otherwise your App wouldn't crash. Are you sure that a HandlerThread which is not running is really the reason? Don't you create HandlerThread objects when your Activity is created?
If your HandlerThreads are waiting on I/O operations, I would consider to try and interrupt them. Simply removing callbacks and messages and asking the Looper to quit, even sending temrination messages to the Handler, will do nothing. The HandlerThread object will still be around until Android kills the process (which may or may not occur). This means that "your app will collect zombie HandlerThread objects" which are probably unreachable. Unless, of course, you can send those HandlerThreads a termination message which arrives on the channel they block on.
It would be much better to re-use the HandlerThread objects. A Service might be the right model to do this.
Also, if Threads survive your Activity, you need to inform them that their communication peer (your Activity) is gone. Otherwise, they may refer to something which is already gone.
The best practices approach would be to remove the callbacks to your handlers in your activities onDestroy(). See this answer for more:
https://stackoverflow.com/a/5038542/1369222
The HandlerThread is stopped when the Looper is quitted. HandlerThread.getLooper().quit() when you stop your activity. (see http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/app/IntentService.java#IntentService.ServiceHandler.%3Cinit%3E%28android.os.Looper%29 for a good example of a proper HandlerThread use)
In Android, runtime error dialog is prompted when error occurs. Is it possible to hide it? Or just hide it in production mode? Since it is showing some error message about the app which should not be exposed to users.
you should avoid your app to reaching the force close, when your app ends up in force close so your main thread has been killed and your app is no longer running and it's not accessible in coding so you can make another thread and handle situation and show custom dialog to the user.
Maybe Acra in Github would help you handle this issue.
You can set a custom handler for uncaught exceptions using Thread.setDefaultUncaughtExceptionHandler(..) on your main thread. There you can do what you need to do, including calling the default behaviour if you use the following pattern:
public class ExceptionHandler implements UncaughtExceptionHandler
{
/**
* The default handler.
*/
private UncaughtExceptionHandler defaultUEH;
/**
* Constructs the instance and sets the default handler to the one currently
* active at the time of construction.
*/
public ExceptionHandler()
{
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}
#Override
public void uncaughtException(Thread thread, Throwable ex)
{
// do your stuff
// if you want to resume with the default behaviour, you call this
defaultUEH.uncaughtException(thread, ex);
}
}
In your Activity/Application:
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
Is there a way to ask Android to return to a previous Activity within my application in the event that another Activity causes an unhandled exception to be thrown?
You can try to use Thread.setDefaultUncaughtExceptionHandler to receive notification when any thread has died due to an unhandled exception. But I'm not sure about Dalvik implementation of that mechanism. It could be possible you would not be able to start another activity from the UncaughtExceptionHandler as the documentation says nothing about thread/process resurrection.
Update
Ok. I tested it and now I'm sure you will NOT be able to return to a previous Activity using the above technique if your application thrown an exception in the UI thread. This happens because that exception would cause application main looper to exit and thus your application would not be able to process any further UI messages.
The only possible way I've found to achieve what you want is the following dirty-hack:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
while (true) {
try {
Log.i("MyLooper", "Starting my looper");
Looper.loop();
} catch (Exception e) {
Log.e("MyLooper", "Caught the exception in UI thread, e:", e);
showPreviousActivity();
}
}
}
private void showPreviousActivity() {
// your implementation of showing the previous activity
}
}
And register MyApplication in your AndroidManifest.xml:
<application android:name=".MyApplication">
…
The implementation of the showPreviousActivity() method is up to you. One of the possible solution would be to keep track of the currently Activity instance in some ActivityTracker class and to call current activity finish() method from the showPreviousActivity code.
Use a try-catch block to catch the exception and startActivity there. You can not go to another activity without catching it.