I'm a newbie in android and I always see Exception when I'm running my code.
So, somebody can tell me Can I call a method before app go to crash anywhere without "try-catch".
This would be better way to handle uncaught exception:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
appInitialization();
}
private void appInitialization() {
defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(_unCaughtExceptionHandler);
}
private UncaughtExceptionHandler defaultUEH;
// handler listener
private Thread.UncaughtExceptionHandler _unCaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
ex.printStackTrace();
// TODO handle exception here
}
};
}
Application is a Base class for those who need to maintain global application state. And hence here, it will be a better place to handle such exceptions.
EDIT:
The above code will handle uncaught exceptions if they are thrown inside UI thread.
If an exception has occurred in worker thread, you can handle it in following way:
private boolean isUIThread(){
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
// 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) {
e.printStackTrace(); // not all Android versions will print the stack trace automatically
if (isUIThread()) {
// exception occurred from UI thread
invokeSomeActivity();
} else { //handle non UI thread throw uncaught exception
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
invokeSomeActivity();
}
});
}
}
I think what you search is the UncaughtExceptionHandler. It is notified whenever an Exception is fired and not catched on its way bubbling up through your application.
See http://www.intertech.com/Blog/android-handling-the-unexpected/ for more details on implementing this in android.
Try this way
1) create class
import android.content.Context;
import android.content.Intent;
import android.os.Process;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;
public class CrashReportHandler implements UncaughtExceptionHandler {
public static void attach(Context context) {
Thread.setDefaultUncaughtExceptionHandler(
new CrashReportHandler(context)
);
}
///////////////////////////////////////////// implementation
private CrashReportHandler(Context context) {
m_context = context;
}
public void uncaughtException(Thread thread, Throwable exception) {
StringWriter stackTrace = new StringWriter();
exception.printStackTrace(new PrintWriter(stackTrace));
//You will get call back here when app crashes.
// from RuntimeInit.crash()
Process.killProcess(Process.myPid());
System.exit(10);
}
private Context m_context;
}
How to use this class?
write this line in your activity onCreate() method
CrashReportHandler.attach(this);
There is method called Uncaught exception which is called just before force close dialog , you can write ur piece of code there .. Please check Using Global Exception Handling on android
Use CrashLytics for crash reporter free of cost and easy to implement
https://www.crashlytics.com/
Related
So I want to intercept the unhandled exceptions and I am doing this by:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
//MY CUSTOM CODE TO SEND LOGS
System.exit(2);
}
});
Is there anyway I can execute my custom code and then resume normal way it handles these exceptions? I believe I am getting some hanging issues since System.exit doesn't seem to be working reliably.
You have to get the default handler first. Then intercept and send the error too the handler. System.exit... is a bad idea.
So first you create a custom exceptionhandler like you did:
public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler defaultUEH;
public CustomExceptionHandler(Thread.UncaughtExceptionHandler defaultUEH) {
this.defaultUEH = defaultUEH;
}
#Override
public void uncaughtException(Thread thread, Throwable ex) {
String stackTrace = Log.getStackTraceString(ex);
String time = new Date(System.currentTimeMillis()).toString();
String message = ex.getMessage();
// send logs...
defaultUEH.uncaughtException(thread, ex);
}
}
So basically in your onCreate method (best used in a custom Application class to have it fall all parts) set the default exception handler if not already set (check not needed in Application):
Thread.UncaughtExceptionHandler defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
if (!(defaultUEH instanceof CustomExceptionHandler)) {
Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(defaultUEH));
}
I wrote it here (remove the BuildConfig.DEBUG check) implemented to directly start the email client. If there is no email client installed, you should catch the ActivityNotFoundException.
I have an application and need to code a custom global uncaught exception handler. I've read all the stackoverflow threads and each one of them is just missing a clear and simple example of how this is to be implemented.
Consider this simple following example:
public static void log(String msg) throws Exception {
String logPath = "/application/logs/java.log";
Calendar c = new GregorianCalendar();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String now = format.format(c.getTime());
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logPath, true)));
out.println(now + " " + msg);
out.close();
}
It throws a standard exception which is just a standard output. How do I implement my own exception which overrides the standard one by something simple as outputing the error into a log file? Obviously the actual application is much larger and we're talking about uncaught exceptions, which is why try/catch blocks is not the option.
UPDATE: If you could please answer with a very clear full example, because I found dozens of examples like the one #RamonBoza provided, yet I have no idea how to implement them, which is what this question is all about.
UPDATE2: So I've tried to test the only example in the answer below, it obviously doesn't work. I've created a new class file "MyRunnable" and pasted the code in it:
package mypackage;
Thread t = new Thread(new MyRunnable());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error(t + " throws exception: " + e);
}
});
t.start();
//outside that class
class MyRunnable implements Runnable(){
public void run(){
throw new RuntimeException("hey you!");
}
}
Needless to say I get a bunch of errors with this. How can something be outside of class anyway?
UPDATE3: This is the solution that finally works:
package mypackage;
public class MyClass {
public static void main(String[] args) throws Exception {
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stacktrace = sw.toString();
System.out.println(stacktrace);
}
});
//main method code
}
//Rest of the methods here
}
You can set UncaughtExceptionHandler for the thread controlling the code above:
// t is the parent code thread
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error(t + " throws exception: " + e);
}
});
Java docs for UncaughtExceptionHandler -
When a thread is about to terminate due to an uncaught exception the
Java Virtual Machine will query the thread for its
UncaughtExceptionHandler using Thread.getUncaughtExceptionHandler()
and will invoke the handler's uncaughtException method, passing the
thread and the exception as arguments
the setUncaughtExceptionHandler is commonly used to free memory or kill threads that the system will not be able to kill, and perhaps, remain zombie.
A real example:
Thread t = new Thread(new MyRunnable());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error(t + " throws exception: " + e);
}
});
t.start();
//outside that class
class MyRunnable implements Runnable(){
public void run(){
throw new RuntimeException("hey you!");
}
}
You can use UncaughtExceptionHandler to handle the exception those causes a thread to terminate abruptly.
Java doc for UncaughtExceptionHandler -
Interface for handlers invoked when a Thread abruptly terminates due
to an uncaught exception. When a thread is about to terminate due to an uncaught exception the Java Virtual Machine will query the thread for its UncaughtExceptionHandler using Thread.getUncaughtExceptionHandler() and will invoke the handler's uncaughtException method, passing the thread and the exception as arguments
You need to implement this interface and set your implementation of UncaughtExceptionHandler for a thread by using method setUncaughtExceptionHandler.
There are two ways you can do this -
setUncaughtExceptionHandler
setDefaultUncaughtExceptionHandler
1) setUncaughtExceptionHandler - This will be a thread specific exception handler. So in case this thread gets terminated by some unhandled exception, this handler will be used.
2) setDefaultUncaughtExceptionHandler - This will be a default exception handler in case there is no specific uncaught exception handler for a thread.
Example -
class MyExceptionHandler implements UncaughtExceptionHandler{
#Override
public void uncaughtException(Thread arg0, Throwable arg1) {
System.out.println("[DEFAULT EXCEPTION HANDLER] Caught some exception");
}
}
class MyThread extends Thread{
public MyThread() {
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("[THREAD SPECIFIC] My exception handler");
}
});
}
public void run(){
throw new RuntimeException();
}
}
public class Test {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
new MyThread().start();
// current thread does not have a thread specific exception handler
throw new RuntimeException();
}
}
You can try setting your own uncaught Exception handler, however I strongly advise against it. If your application has parts that can potentially break and if that exception is then not properly handled at the location where your code breaks, your entire program will malfunction frequently.
Let's imagine we have a simple Android application, which connects to a remote service via IPC, schedules a relatively long task, then continues working while awaiting for callback with some results. AIDL interfaces:
IRemoteService.aidl
package com.var.testservice;
import com.var.testservice.IServCallback;
interface IRemoteService {
void scheduleHeavyTask(IServCallback callback);
}
IRemoteService.aidl
package com.var.testservice;
interface IServCallback {
void onResult(int result);
}
Code for activity:
package com.var.testclient;
import com.var.testservice.IServCallback;
import com.var.testservice.IRemoteService;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
public class MainActivity extends Activity {
private static final String TAG = "TestClientActivity";
private IServCallback.Stub servCallbackListener = new IServCallback.Stub(){
#Override
public void onResult(int result) throws RemoteException {
Log.d(TAG, "Got value: " + result);
}
};
private ServiceConnection servConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = IRemoteService.Stub.asInterface(binder);
}
#Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
};
private IRemoteService service;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(!bindService(new Intent(IRemoteService.class.getName()), servConnection, Context.BIND_AUTO_CREATE)){
Log.d(TAG, "Service binding failed");
} else {
Log.d(TAG, "Service binding successful");
}
}
#Override
protected void onDestroy() {
if(service != null) {
unbindService(servConnection);
}
super.onDestroy();
}
public void onButtonClick(View view){
Log.d(TAG, "Button click");
if(service != null){
try {
service.scheduleHeavyTask(servCallbackListener);
} catch (RemoteException e) {
Log.d(TAG, "Oops! Can't schedule task!");
e.printStackTrace();
}
}
}
}
Code for service:
package com.var.testservice;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
public class TestService extends Service {
private static final String TAG = "TestService";
class TestServiceStub extends IRemoteService.Stub {
private IServCallback servCallback;
//These 2 fields will be used a bit later
private Handler handler;
private int result;
//The simpliest implementation. In next snippets I will replace it with
//other version
#Override
public void scheduleHeavyTask(IServCallback callback)
throws RemoteException {
servCallback = callback;
result = doSomethingLong();
callback.onResult(result);
}
private int doSomethingLong(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
return 42;
}
}
}
#Override
public IBinder onBind(Intent intent) {
return new TestServiceStub();
}
}
This version, while being really dumb (it makes UI thread from application hang for 5 seconds, causing ANR), it successfully executes all calls via IPC, delivering result to activity.
Problems start if I try to put calculations into separate thread:
#Override
public void scheduleHeavyTask(IServCallback callback)
throws RemoteException {
servCallback = callback;
Runnable task = new Runnable(){
#Override
public void run() {
result = doSomethingLong();
try {
Log.d(TAG, "Sending result!");
servCallback.onResult(result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
new Thread(task).start();
}
In this case the callback is just not delivered to activity: service successfully calls servCallback.onResult(result);, but nothing is called within activity. No exceptions, no clues, no survivors: perfect invocation murder. I couldn't find any information about possible cause of such behavior, so I'd be grateful if someone could clarify what happens here. My suggestion's that there's some kind of security mechanism, tracking which exact threads were bound, and ignoring "unsafe" calls from other threads (something similar happens when we try to mess with UI elements from non-UI thread), but I can't be sure.
The most obvious solution is to post callback invocation to the bound thread, so I made this:
#Override
public void scheduleHeavyTask(IServCallback callback)
throws RemoteException {
Log.d(TAG, "Schedule request received.");
servCallback = callback;
if(Looper.myLooper() == null) {
Looper.prepare();
}
handler = new Handler();
Runnable task = new Runnable(){
#Override
public void run() {
result = doSomethingLong();
Log.d(TAG, "Posting result sender");
handler.post(new Runnable(){
#Override
public void run() {
try {
Log.d(TAG, "Sending result!");
servCallback.onResult(result);
} catch (RemoteException e) {
e.printStackTrace();
}
Looper.myLooper().quit();
Log.d(TAG, "Looper stopped");
}
});
}
};
new Thread(task).start();
Looper.loop();
}
Here I faced 2 more problems:
I had to call Looper.loop() to enable processing of callback runnables, but it blocks IPC, so I have the same result as in the beginning - no actual multithreading;
Registering for callback second time (after first cycle finished and returned value) results in exception:
java.lang.RuntimeException: Handler (android.os.Handler) sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage
at android.os.Handler.sendMessageAtTime
at android.os.Handler.sendMessageDelayed
at android.os.Handler.post
at com.var.testservice.TestService$TestServiceStub$1.run
at java.lang.Thread.run
This lefts me completely puzzled: I make a fresh instance from actual Looper, how can it point to dead thread?
The whole idea of service being able of queueing tasks and making callbacks when they finish doesn't sound insane to me, so I hope someone more experienced could explain me:
Why can't I actually make IPC calls from different threads?
What's wrong with my Handler?
What instruments/architecture should I use to make a clean, proper queue mechanism, so it could call IPC methods on the right thread without constantly calling Looper.loop()/Looper.quit()?
Thank you.
I can't explain why your program isn't working. But the version involving threads and an asynchronous callback:
#Override
public void scheduleHeavyTask(IServCallback callback)
throws RemoteException {
servCallback = callback;
Runnable task = new Runnable(){
#Override
public void run() {
result = doSomethingLong();
try {
Log.d(TAG, "Sending result!");
servCallback.onResult(result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
new Thread(task).start();
}
should work just fine.
Here's how Android arranges threads for AIDL and other types of Binder transaction.
If the caller and the callee are in the same process, it becomes a simple method call. So, you should fine that scheduleHeavyTask is called from the very same thread as onButtonClick. Similarly, you should fine that the call to onResult should be a simple method call, from the thread running the task.
If the caller and callee are in different processes, Android will run the Binder transactions from a pool of threads within the callee process (they are called Binder #1 etc.) Even here it's quite clever - so if onButtonClick called scheduleHeavyTask which called back to onResult from the same thread, then onButtonClick would appear directly to call onResult within the caller process.
There are absolutely no mechanisms to avoid calls from "unsafe" or "unbound" threads - so this simple approach you posted should work. As you say, it's a common pattern, and I've used it lots of times. I'd therefore recommend proceeding with this rather than fiddling with extra loopers and handlers.
Here are some ideas:
Run it in a debugger. Assuming your service and activity are in the same process, you should be able to set breakpoints and see sensible method calls taking place.
Even if you can't, fire up ddms from the command line, or show the Devices and Threads views within Eclipse. This will give you a view of exactly what each thread is doing - you can get a callstack. It's normally possible to use this even in cases where a full-on debugger would be inconvenient.
Do you have the word synchronized anywhere? What could be happening is that onResult wants to go ahead and run, but it's blocked on some monitor. As soon as it becomes unblocked, it might well run.
If I invoke the run() method on a Thread and the run() method throws an uncaught Exception what would be the outcome ?
Who catches this Exception? Does the Exception even get caught?
If there is an exception handler installed for the ThreadGroup, the JVM passes the exception to it. If it's an AWT thread, you can install an event handler for otherwise unhandled exceptions. Otherwise the JVM handles it.
Example of a thread group with a custom handler and how to use it:
public class MyThreadGroup extends ThreadGroup {
public MyThreadGroup() {
super("My Thread Group");
}
public void uncaughtException(Thread t, Throwable ex) {
// Handle exception
}
}
Thread t = new Thread(new MyThreadGroup(), "My Thread") { ... };
t.start();
Example of using an AWT exception handler:
public class MyExceptionHandler {
public void handle(Throwable ex) {
// Handle exception
}
public void handle(Thread t, Throwable ex) {
// Handle exception
}
}
System.setProperty("sun.awt.exception.handler", MyExceptionHandler.class.getName());
If you've submitted the Runnable to an ExecutorService you can catch the Exception as wrapped inside a ExecutionException. (Highly recommended over simply calling run())
It can if you assign it to a ThreadGroup that implements the uncaughtException(Thread, Throwable) method.
We'd like a trace in our application logs of these exceptions - by default Java just outputs them to the console.
Since Java 7, you have to do it differently as the sun.awt.exception.handler hack does not work anymore.
Here is the solution (from Uncaught AWT Exceptions in Java 7).
// Regular Exception
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
// EDT Exception
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
// We are in the event dispatching thread
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
}
});
There is a distinction between uncaught exceptions in the EDT and outside the EDT.
Another question has a solution for both but if you want just the EDT portion chewed up...
class AWTExceptionHandler {
public void handle(Throwable t) {
try {
// insert your exception handling code here
// or do nothing to make it go away
} catch (Throwable t) {
// don't let the exception get thrown out, will cause infinite looping!
}
}
public static void registerExceptionHandler() {
System.setProperty('sun.awt.exception.handler', AWTExceptionHandler.class.getName())
}
}
A little addition to shemnons anwer:
The first time an uncaught RuntimeException (or Error) occurs in the EDT it is looking for the property "sun.awt.exception.handler" and tries to load the class associated with the property. EDT needs the Handler class to have a default constructor, otherwise the EDT will not use it.
If you need to bring a bit more dynamics into the handling story you are forced to do this with static operations, because the class is instantiated by the EDT and therefore has no chance to access other resources other than static. Here is the exception handler code from our Swing framework we are using. It was written for Java 1.4 and it worked quite fine there:
public class AwtExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(AwtExceptionHandler.class);
private static List exceptionHandlerList = new LinkedList();
/**
* WARNING: Don't change the signature of this method!
*/
public void handle(Throwable throwable) {
if (exceptionHandlerList.isEmpty()) {
LOGGER.error("Uncatched Throwable detected", throwable);
} else {
delegate(new ExceptionEvent(throwable));
}
}
private void delegate(ExceptionEvent event) {
for (Iterator handlerIterator = exceptionHandlerList.iterator(); handlerIterator.hasNext();) {
IExceptionHandler handler = (IExceptionHandler) handlerIterator.next();
try {
handler.handleException(event);
if (event.isConsumed()) {
break;
}
} catch (Throwable e) {
LOGGER.error("Error while running exception handler: " + handler, e);
}
}
}
public static void addErrorHandler(IExceptionHandler exceptionHandler) {
exceptionHandlerList.add(exceptionHandler);
}
public static void removeErrorHandler(IExceptionHandler exceptionHandler) {
exceptionHandlerList.remove(exceptionHandler);
}
}
Hope it helps.
There are two ways:
/* Install a Thread.UncaughtExceptionHandler on the EDT */
Set a system property:
System.setProperty("sun.awt.exception.handler",MyExceptionHandler.class.getName());
I don't know if the latter works on non-SUN jvms.
--
Indeed, the first is not correct, it's only a mechanism for detecting a crashed thread.