Crashlytics and AsyncTask - android

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

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.

Related

How to override handleUncaughtException without changing its functionallity

I asked this question some time back on Stackoverflow, the answer worked for me, It overrides thehandleUncaughtException, I save the exception and throws the default Unfortunately app has stopped working, but when i integrated this in my app, I am facing an issue.
This is the answer i got.
private Thread.UncaughtExceptionHandler defaultExceptionHandler;
public void registerCrash(){
defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler(){
#Override
public void uncaughtException (Thread thread, Throwable e){
handleUncaughtException (thread, e);
if(defaultExceptionHandler != null){
defaultExceptionHandler.uncaughtException(thread, e);
}
}
});
}
What it does, first it goes to handleUncaughtException (thread, e); i save the crash log in this method, then it reads this line
if(defaultExceptionHandler != null){
defaultExceptionHandler.uncaughtException(thread, e);
}
here we throw uncaught exception again, so it goes to the first line again, and again saves the exception, and this goes in loop, and application becomes not responding.
What i want is to save crash log, and then show the default Unfortunate message to user.
EDIT
On Application launch it reads this;
defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
When application crashes, it reads these lines
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler(){
#Override
public void uncaughtException (Thread thread, Throwable e){
handleUncaughtException (thread, e); //Custom Method
if(defaultExceptionHandler != null){
defaultExceptionHandler.uncaughtException(thread, e);
}
}
So it first goes to handleUncaughtException() there i have provided custom implementation, then it goes to this;
if(defaultExceptionHandler != null){
defaultExceptionHandler.uncaughtException(thread, e);
}
The defaultExceptionHandler is never null; So it goes in a loop in case of multiple crashes.
I have tried adding count there, but it was 0 each time.
The most likely explanation is that your registerCrash() method is being called twice.
The first time, you register Handler 1; there is no default handler at this point, so it sets defaultExceptionHandler to null. The second time, you register Handler 2, and then update defaultExceptionHandler to point to Handler 1.
On an uncaught exception, Handler 2 gets invoked first. It calls your custom handler method, then invokes defaultExceptionHandler, which now points to Handler 1.
Handler 1 gets invoked. It calls your custom handler method a second time, then it invokes defaultExceptionHandler, which now points to itself. This step repeats until your stack overflows.
I suggest two changes. First, add a guard to ensure you only register your crash handler once. Second, don't store the fallback handler in a field; capture it in a closure so the value seen by your handler never changes.
private static final AtomicBoolean CRASH_HANDLER_REGISTERED = new AtomicBoolean();
public void registerCrash() {
if (CRASH_HANDLER_REGISTERED.compareAndSet(false, true)) {
final Thread.UncaughtExceptionHandler defaultHandler =
Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable e) {
handleUncaughtException(thread, e); // Custom Method
if (defaultHandler != null) {
defaultHandler.uncaughtException(thread, e);
}
}
}
);
}
}
I suggest you to try another approach, avoid overriding exceptions, catch it and retrive the error code, and do this:
when x code with x conditions verify, do that

How do i add a delay to program before running selection query to avoid bind value being null?

I keep getting an illegal argument exception when running my app. However, this happens prior to the Toast messages coming up and that's why I think I need a delay.
Prior to adding on the DatabaseHelper class, my app was running and the proper value was coming up on both Toast messages, the one in the MainActivity and the one showing the intent value passed in the DisplayResult activity.
I'm not sure what to do at this point.
Just do a thread sleep in a runnable.
int timeYouWantToSleep = 60000;
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(timeYouWantToSleep);
//do your work here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
If this doesn't work, you know it's not a delay that you need.

Why does my WeakReference gets NULL inside my AsyncTask?

I have spent a lot of hours trying to reproduce and understand the cause of this problem, with no success in either of these goals.
I have tried to leave only the code related to the problem, but I believe a few minutes are still necessary to understand the problem and context. I hope that someone will be able to spot the problem in my implementation or at least help me understand the cause.
Description of the application:
Word game where you play against the computer. After the computer has laid a word on the board, the definition of this word is fetched online in an AsyncTask and displayed in a TextView
How I discovered the issue:
I use ACRA for crash and error reporting (great free tool by the way). It sends me reports for each unexpected situtation (this one does not lead to a crash). I have been receiving many reports of errors 1,2,3 and 4 (see code)
Some bad reviews on Google Play tend to show that some users do not see the definition even though they are connected to Internet. (I am pretty sure this functional bug is related to the previously mentioned errors, though I cannot prove it)
A word on the code design:
After reading a lot on memory leaks in Android, I have decided to make the AsyncTask that retrieves the definition online a static inner class (even though my main activty currently does not support rotations, which are the main causes of leaks: I put in my Manifest android:screenOrientation="portrait").
I need access to the parent Activity from this AsyncTask because I retrieve strings from the resources, and perform some changes on the UI in onPostExecute().
Hence, I use a WeakReference in the AsyncTask which is pointing to the parent Activity. This should prevent memory leaks in case the Activity is recreated or killed while theAsyncTask` is still running.
What exactly is the problem:
The WeakReference or the return of its get() method is null in
some unexplained situations (I suspect it impacts more than 1% of the games or
players) (see code)
All kinds of devices and Android versions are impacted, and I often see several occurences coming from the same device)
I have never been able to reproduce these errors (the most obvious try was exiting the activity while the definition is being downloaded, but this didn't cause any error)
Meaningful parts of my code:
public class GameActivity extends Activity {
private TextView _definition; //inflated from XML in onCreate()
private ProgressDialog _pDialog; //created in onCreate()
private Handler _handlerToDelayDroidMove = new Handler();
private Handler _handlerToDelayProgressDialog = new Handler();
private Handler _handlerToDelayDefinitionClosure = new Handler();
public void onClickValidatePlayerMoveAndTriggerDroidMove(View v) {
int score = _arbitre.validatePlayerMoveAndReturnScore(_listOfLetters);
toast(String.format(getResources().getString(R.string.player_word_score), score));
// ***** Only start Droid move when previous toast has been displayed ****
timedDroidPlayWithSpinner();
}
private void timedDroidPlayWithSpinner() {
_handlerToDelayProgressDialog.removeCallbacks(_droidThinkingDialogRunnable);
_handlerToDelayDroidMove.removeCallbacks(_droidPlayRunnable);
_handlerToDelayProgressDialog.postDelayed(_droidThinkingDialogRunnable, 1500);
_handlerToDelayDroidMove.postDelayed(_droidPlayRunnable, 1500 + DUMMY_DELAY);
}
private Runnable _droidThinkingDialogRunnable = new Runnable() { //Show a "Droid is thinking spinner dialog"
public void run() {
_pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
_pDialog.setMessage(getResources().getString(R.string.droid_thinking));
_pDialog.setCancelable(false);
_pDialog.show();
}
};
private Runnable _droidPlayRunnable = new Runnable() {
public void run() {
String word = playBestMoveAndUpdateGUI(); // Droid move (CPU intensive, can take several seconds)
saveGameStateToPrefs();
_pDialog.dismiss(); //Hide "Thinking dialog")
new SearchDefinitionTask(GameActivity.this).execute(word);
}
};
private Runnable _hideDefinitionRunnable = new Runnable() {
public void run() {
_definition.startAnimation(_slideUpAnim);
_definition.setVisibility(View.GONE);
}
};
// Made static so we are sure if does not reference the Activity (risk of leak)
public static class SearchDefinitionTask extends AsyncTask<String, Void, String[]> {
private WeakReference<GameActivity> weakRefToGameActivity;
public SearchDefinitionTask(GameActivity context) { //Save a weak reference to the Activity
super();
weakRefToGameActivity = new WeakReference<GameActivity>(context);
}
protected String[] doInBackground(String... words) {
try {
DefFetcherInterface defFetcher = null;
Language l = weakRefToGameActivity.get()._dictionaryId;
defFetcher = new OnlineDefinitionFetcher(l);
return defFetcher.getDefinition(words[0]);
} catch (Exception e) { // Typical exceptions are due to lack of internet connectivity
Log.e("Definition fetch error: ", e.toString());
String[] ret = { "", "" };
ret[0] = mots[0];
if (weakRefToGameActivity == null) { // !!! This occurs in ~0.3% of the games !!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 1: weakRef is NULL"));
return ret;
}
if (weakRefToGameActivity.get() == null) { !!! This occurs in ~1% of the games !!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 2: weakRef.get() is NULL"));
return ret;
}
// If we get here we still have a reference on our Activit/context, so let's show a decent error message
ret[1] = weakRefToGameActivity.get().getResources().getString(R.string.no_connection);
return ret;
}
}
protected void onPostExecute(String[] result) {
if (result[0] != "") { //Don't send another error report if WeakRef was already NULL in doInBackground()
if (weakRefToGameActivity == null) { !!! This occurs in ~0.5% of the games !!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 3: weakRef is NULL"));
} else if (weakRefToGameActivity.get() == null) { !!!!!!!! This occurs in ~1% of the games !!!!!!!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 4: weakRef.get() is NULL"));
} else {
// Everything is fine, show a box with the definition of the word for a few seconds
//(with animation to make the box appearing from the top of the screen)
weakRefToGameActivity.get()._definition.setVisibility(ImageView.VISIBLE);
weakRefToGameActivity.get()._handlerToDelayDefinitionClosure.removeCallbacks(weakRefToGameActivity.get()._hideDefinitionRunnable);
weakRefToGameActivity.get()._definition.setText(Html.fromHtml("<b>" + result[0].toUpperCase() + "</b> " + result[1]));
weakRefToGameActivity.get()._definition.startAnimation(weakRefToGameActivity.get()._slideDownAnim);
weakRefToGameActivity.get()._handlerToDelayDefinitionClosure.postDelayed(weakRefToGameActivity.get()._hideDefinitionRunnable,
DURATION_OF_DEFINITION);
}
}
}
}
}
Any idea of what could go wrong or how to reproduce?
Sebastien, maybe you can try to check the onDestroy is never called for your Activity... The activity can be restarted when the screen is rotated (which you already handle), but there are other configuration changes that may cause the same behavior.
Another pretty common one is to take the keyboard out on some phones, but there are others that are even more obscure to me. You can see the list there
Beside that, I really don't see anything wrong in your code and cannot imagine what else could cause your trouble.
The worst ones are your errors 1 and 3. Can you check in the constructor that weakRefToGameActivity is not null after it is created? (and if it is null, what about the context argument).
Please post updates once you find the root cause of your problem.
Bonne chance.

My App works on android 2.3.3 to android 3.1 but stops with error on 4.0 +

I just publicated yesterday my first android application.
I did not tested on android 4.0 and my friend just told me my app is crashes on his galaxy S2 (4.0.3 )
It is crashing after a few seconds in my splash screen activity, its just a few lines of code maybe you guys can check it:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen);
try
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
overridePendingTransition(0 , 0);
// thread for displaying the SplashScreen
Thread splashTread = new Thread() {
#Override
public void run() {
try {
int waited = 0;
while(_active && (waited < _splashTime)) {
sleep(100);
if(_active) {
waited += 100;
}
}
} catch(InterruptedException e) {
// do nothing
} finally {
// finish();
try
{
/*
Intent i = new Intent();
i.setClass(SplashScreen.this, MainActivity.class);
startActivity(i);
finish();
*/
}
catch(Exception e)
{
ki(e);
}
stop();
}
}
};
splashTread.start();
}
catch(Exception ex)
{
ki(ex);
}
}
#Override
public void onBackPressed() {
return;
}
//Toaster
public void ki(Exception message)
{
Toast myToast = Toast.makeText(getApplicationContext(), message.toString(), 1);
myToast.show();
}
Works verry well on Android 2.3 to 3.1 but i cant figure out whats the problem with 4.0+
Please help thank you!
Edit:
If i delete my thread everything works well. So me new question is... Whats new with threads in 4.0 ? I just ran a thread that does nothing and even i got the crash.
Thread.stop(), resume(), and suspend() no longer works with Android 4.0. The source code is below:
/**
* Requests the receiver Thread to stop and throw ThreadDeath. The Thread is
* resumed if it was suspended and awakened if it was sleeping, so that it
* can proceed to throw ThreadDeath.
*
* #deprecated because stopping a thread in this manner is unsafe and can
* leave your application and the VM in an unpredictable state.
*/
#Deprecated
public final void stop() {
stop(new ThreadDeath());
}
/**
* Throws {#code UnsupportedOperationException}.
*
* #throws NullPointerException if <code>throwable()</code> is
* <code>null</code>
* #deprecated because stopping a thread in this manner is unsafe and can
* leave your application and the VM in an unpredictable state.
*/
#Deprecated
public final synchronized void stop(Throwable throwable) {
throw new UnsupportedOperationException();
}
A lot of application crashes on Android 4.0 because of this. This is not Google's fault; from years ago Java SDK has discouraged using stop() on a thread.
Quote from changelog:
Commit: a7ef55258ac71153487357b861c7639d627df82f [a7ef552]
Author: Elliott Hughes <enh#google.com>
Date: 2011-02-23 6:47:35 GMT+08:00
Simplify internal libcore logging.
Expose LOGE and friends for use from Java. This is handy because it lets me use
printf debugging even when I've broken String or CharsetEncoder or something
equally critical. It also lets us remove internal use of java.util.logging,
which is slow and ugly.
I've also changed Thread.suspend/resume/stop to actually throw
UnsupportedOperationException rather than just logging one and otherwise
doing nothing.
Bug: 3477960
Change-Id: I0c3f804b1a978bf9911cb4a9bfd90b2466f8798f
As #Yuku says, Thread.stop() isn't somehow broken in ICS it's specifically changed to throw an exception as it's unsafe:
http://developer.android.com/reference/java/lang/Thread.html#stop()
public final synchronized void stop (Throwable throwable)
Since: API Level 1 This method is deprecated. because stopping a
thread in this manner is unsafe and can leave your application and the
VM in an unpredictable state.
Throws UnsupportedOperationException.
Throws NullPointerException if throwable() is null
If you want you're thread to be forcefully stopped instead use threadName.interrupt() while external to your thread. Program in a natual end to you're threads lifecycle so that it stops naturally when it's task is complete.
In your example you can simply delete the command stop() since the thread will naturally cease execution at the end of it's run() method.
EDIT finish() is a call to your Activity to finish, not your Thread. In the above example the Thread would exit naturally anyway but please don't be confused with stopping a Thread and finishing an Activity as they are vastly different things.
I had the same issue using stop() on Android 4.0. Try using finish() instead, that solved my problem.
I guess that stop() is no longer working on ICS.
My tutorial at droidnova.com is not updated to work on ICS, sorry, hadn't time for that. Today I would use a handler instead of the separate thread. Much easier to use and more robust.

Using Global Exception Handling on android

Is there a code example, or a tutorial on how to use the Thread.setDefaultUncaughtExceptionHandler method? Basically I'm trying to display a custom alert dialog, whenever an exception is thrown, in my application. Is it possible to do this? I know it's a little bit tricky to display something on the screen, if the exception is thrown in the UI thread but I don't know any work around for this.
Basic Example for someone who comes to this page with a solution :)
public class ChildActivity extends BaseActivity {
#SuppressWarnings("unused")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int a=1/0;
}
}
Class for handling error:
public class BaseActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
Log.e("Alert","Lets See if it Works !!!");
}
});
}
}
Here's a variant of the answer by Mohit Sharma with the following improvements:
Doesn't cause the app/service to freeze after error handling
Lets Android do its normal error handling after your own
Code:
public class BaseActivity extends Activity {
#Override
public void onCreate() {
super.onCreate();
final Thread.UncaughtExceptionHandler oldHandler =
Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(
Thread paramThread,
Throwable paramThrowable
) {
//Do your own error handling here
if (oldHandler != null)
oldHandler.uncaughtException(
paramThread,
paramThrowable
); //Delegates to Android's error handling
else
System.exit(2); //Prevents the service/app from freezing
}
});
}
}
For those who just want to see exception details when your app crashes on device (in debug config). This is application class:
private Thread.UncaughtExceptionHandler oldHandler;
#Override
public void onCreate() {
super.onCreate();
if (!BuildConfig.DEBUG)
return;
oldHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
try {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_TEXT, sw.toString());
intent.setType("text/plain");
startActivity(intent);
} catch(Exception ex) {
ex.printStackTrace();
} finally {
if (oldHandler != null)
oldHandler.uncaughtException(t, e);
else
System.exit(1);
}
});
}
It uses external app as your UI thread might not working anymore.
Keep in mind that the The RuntimePermission("setDefaultUncaughtExceptionHandler") is checked prior to setting the handler and make sure you cause the process to halt afterwards, by throwing an uncaught exception, as things could be in an uncertain state.
Do not display anything, indeed the UI thread might have been the one that crashed, do write a log and/or send the details to a server, instead. You might want to check out this question and its answers.
I just wanted to point out my experience so far. I am using the solution suggested by https://stackoverflow.com/a/26560727/2737240 to flush the exception into my log file before giving control to the default exception handler.
However, my structure looks like this:
BaseActivity
|
_______________________
| | |
Activity A Activity B Activity C
final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable e) {
handleUncaughtException(thread, e, defaultEH);
}
});
where handleUncaughtException(thread, e, defaultEH); writes to the log and hands the call over to the original UncaughtExceptionHandler.
So what happened by using this code was the following:
Activity A is instantiated
New Default Exception Handler (DEH) is now my log handler + the old DEH
Activity B is instantiated
New DEH is now my log handler + the old DEH (log handler + original DEH)
Activity C is instantiated
New DEH is now my log handler + the old DEH (log handler + log handler + original DEH)
So it's a chain growing infinitely causing two problems:
The specified custom code (in my case writing to the log file) will be called multiple times, which is not the desired action.
The reference of defaultEh is kept in the heap even after the activity has been finished, because it is used by the reference chain so the worst thing that could happen is an out of memory exception.
Therefore I added one more thing to finally make this work without issues:
private static boolean customExceptionHandlerAttached = false;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!customExceptionHandlerAttached) {
final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable e) {
handleUncaughtException(thread, e, defaultEH);
}
});
customExceptionHandlerAttached = true;
}
}
With this solution we can make sure to:
add a custom exception handler for our desired action
ensure that this action is only triggered once
allowing garbage collector to dispose our activity completely by calling finish()
if you want use this library
https://github.com/selimtoksal/Android-Caught-Global-Exception-Library
create your TransferObject not all in your activities just use in Base activity

Categories

Resources