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());
Related
I have set an UncaughtExceptionHandler, so that I can write out stack traces to disk when my app crashes. I set this handler like this:
if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
exceptionHandler = new CustomExceptionHandler(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString(),
null, this);
Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);
}
where CustomExceptionHandler implements UncaughtExceptionHandler. I keep the instance in my Activity, so I can use it for some other functionality (deleting the stack traces, retrieving them, etc).
I call the above piece of code in the onCreate of my Activity, but it seems to only trigger the first time any Activity is run.
I see the Thread.setDefaultUncaughtExceptionHandler call is static though, does that mean I can only set that handler only once in my app? Or can I set it per thread?
From docs
* Sets the default uncaught exception handler. This handler is invoked in
* case any Thread dies due to an unhandled exception.
Yep, this handler is global and you need to set it once per app
Is UncaughtExceptionHandler set application wide?
Yes. If you set it in an activity and the activity is destroyed the handler code in the activity may not exist any more.
I have set the handler in the Application-onCreate (not in the Activity) so it works for all Activities that belong to the Application to write crash logs.
For details see How to change crash message in android(if possible)
Here is the gpl-v3+ code for my crashlogger that writes logcat entries to file.
It is initialized in Application.onCreate like this
public class AndroFotoFinderApp extends Application {
private LogCat mCrashSaveToFile = null;
#Override public void onCreate() {
super.onCreate();
mCrashSaveToFile = new LogCat(this, Global.LOG_CONTEXT, HugeImageLoader.LOG_TAG,
PhotoViewAttacher.LOG_TAG, CupcakeGestureDetector.LOG_TAG,
FotoLibGlobal.LOG_TAG, ThumbNailUtils.LOG_TAG, IMapView.LOGTAG,
ExifInterface.LOG_TAG, ImageMetaReader.LOG_TAG);
}
}
where the constants Global.LOG_CONTEXT, HugeImageLoader.LOG_TAG, ...
are android logging tags of different moduls of my code use like this
Log.d(HugeImageLoader.LOG_TAG, "some log message from modul HugeImageLoader)
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.
}
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);
I'm using ACRA in my android application.
But I find that when exception happens within Application#onCreate() method,it only save the report file,rather than raising the dialog to send it.
It there something wrong with my code?
#ReportsCrashes(formKey="")
public class MyAndroidApplication extends Application
{
public void onCreate()
{
ACRAConfiguration config = ACRA.getConfig();
config.setMailTo("test#test.com");
config.setResToastText(R.string.acra_toast);
config.setResDialogText(R.string.acra_dlg_txt);
config.setResDialogCommentPrompt(R.string.acra_dlg_comment_prpmpt);
try
{
config.setMode(ReportingInteractionMode.DIALOG);
}
catch (ACRAConfigurationException e)
{
logger.error("fail to config ACRA", e);
return;
}
ACRA.setConfig(config);
ACRA.init(this);
someMethodThrowsException();
}
}
The onCreate of the Application is called before any Activity is created and does not have a UI, therefore ACRA cannot display a dialog. From the android docs for onCreate
Called when the application is starting, before any activity, service,
or receiver objects (excluding content providers) have been created.
Implementations should be as quick as possible (for example using lazy
initialization of state) since the time spent in this function
directly impacts the performance of starting the first activity,
service, or receiver in a process. If you override this method, be
sure to call super.onCreate().
So, be sure to call super.onCreate(), which your example above is missing, and you should not be doing a whole lot in there that would cause exceptions.
I'm seeing two problems with your code.
You don't call super.onCreate() after initializing ACRA
Your class should have tha annotation #Reportscrashes even if the parameters are set at runtime. Otherwise you will get an error in logcat saying ACRA#init called but no ReportsCrashes annotation on Application
Also, I'm not sure if the Application can show a dialog because it has no UI layout associated with it. Toast reporting works fine if you change both points above.
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.