ACRA cound not handle exception happens within Application#onCreate() - android

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.

Related

Is UncaughtExceptionHandler set application wide?

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)

How does app know if it started from a crash

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.
}

What is the correct way to dispose of objects when android app crashes?

I wrote a game using libgdx on Android. When my app crashes I still can hear the music play. I think that I forgot to dispose something.
I use assetsmanager to load my resources. I call assetsmanger dispose function in the game class in dispose function of it. I think that it should stop the music and dispose of it.
what I'm doing wrong?
Originally the recommendation would be to release resources using the life cycle methods like "onPause", "onStop", "onDestroy", however, since in some specific cases like this one where the app is crashing and for any reason you just don't get the chance to release resources, there's a last resource that you can use:
public class MyApplication extends Application
{
public void onCreate ()
{
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException (Thread thread, Throwable e)
{
//Do here whatever you want to do when the app crashes
}
});
}
}
The "Thread.UncaughtExceptionHandler" gives you the chance to get a callback when an exception was propagated without being handled at any level of the stack, hence, it gives you the chance to do things like "logging the crash to a server" or in your case you might be able to use it to release some extra resources.
Hope it Helps!
Regards!

LicenseChecker checkAccess leaks ServiceConnection

I am receiving this exception in LogCat every time I press the Back button in my app:
Activity has leaked ServiceConnection
com.android.vending.licensing.LicenseChecker#471cc039 that was
originally bound here
The code responsible for this leak in onCreate() is:
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
mChecker.checkAccess(mLicenseCheckerCallback);
How do I get rid of this leak?
I tried not assigning MyLicenseCheckerCallback to a member, thinking perhaps when the activity goes onPause() the reference to the callback is responsible for the leak:
mChecker.checkAccess(new MyLicenseCheckerCallback());
But that didn't get rid of the leak.
Update: Thanks to #zapl's comment below, I looked at Google's LicenseChecker.java:
/** Unbinds service if necessary and removes reference to it. */
private void cleanupService() {
if (mService != null) {
try {
mContext.unbindService(this);
} catch (IllegalArgumentException e) {
// Somehow we've already been unbound. This is a non-fatal error.
Log.e(TAG, "Unable to unbind from licensing service (already unbound)");
}
mService = null;
}
}
At first I thought that I may be neglecting to call it, but I double-checked and I am calling mChecker.onDestroy(); in my activity's onDestroy().
I also checked onDestroy() in LicenseChecker.java and it is calling unbindService:
/**
* Inform the library that the context is about to be destroyed, so that
* any open connections can be cleaned up.
* <p>
* Failure to call this method can result in a crash under certain
* circumstances, such as during screen rotation if an Activity requests
* the license check or when the user exits the application.
*/
public synchronized void onDestroy() {
cleanupService();
mHandler.getLooper().quit();
}
So, what is really going on?
Is this a bug in LVL?
I just got the same problem, and with your update and zapl's comment I figured up that the problem is the emulator you are using.
This Emulators don't have the Google Play APIs, and the LVL can't bind to the service, leaving a connection open, at the end LVL can't close it with the onDestroy call.
Just create a new AVD using Google APIs instead of Android x.x and try your code there, if you donĀ“t find the Google APIs in the Target pulldown when creating the new AVD download it with the Android SDK Manager.
I have also met the same problem later I got to know that i havn't added that android permission com.android.vending.CHECK_LICENSE . After correcting this my was problem is now solved. Try adding this line your android manifest
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
Just put
mChecker.onDestroy();
on your onDestroymethod of the activity that declares and uses the mChecker.
While Google's code in LicenceChecker looks like this:
public synchronized void onDestroy() {
cleanupService();
mHandler.getLooper().quit();
}
I don't know about google's LicenceChecker, but you should call StopService() before exit the Activity otherwise the service is still running and leaks memory.

Avoid Service callback when Activity gets closed and re-opened

I have a LocalService that exposes a Binder with some APIs. I create a Service Listener, just like this:
if (dataServiceListener == null) {
dataServiceListener = new DataServiceListener();
mainActivity.getApplicationContext().bindService
(new Intent(mainActivity, LocalService.class),
dataServiceListener.svcConn, mainActivity.BIND_AUTO_CREATE);
}
After I call the method that the Binder in dataServiceListener exposes, I get the response in the dataServiceListener onResult() method. Up to this point, no kind of issues, everything is working.
Some sort of problem occurs when I close the Activity that is waiting for the Service Listener callback and immediately reopen it. Even though I re-instantiate the dataServiceListener in onCreate(), I get two callbacks instead of one, the old one from the destroyed Activity and the latter (right) one; this way the results mix up on the UI.
Is there a way to tell the Service or the Service Listener that when the activity finishes, the callbacks must be avoided. Or maybe even destroy the ServiceListener objects.
I think this is the issue that Mark L. Murphy (Commonsware) described in "The Busy Coder's Guide to Android Development":
The biggest catch is to make sure that the activity retracts the listeners when it is done.
How can I do this? Is there a way to get rid of the useless listeners when the activity finishes?
Thank you!
I had the same issue. I was working in a remote sevice using AIDL. I got this problem when i am trying do unregister my listeners using the remove method from ArrayList Collection inside a foreach loop, because I was not using asBinder in the comparision. Searching fora solution, I find out the RemoteCallbackList class in Android API. This class does exactly what i needed, and what i think you should do, on a easy way, taken all reponsabilites for the hard work that involves this task.
From the Android API:
To use this class, simply create a single instance along with your service, and call its register(E) and unregister(E) methods as client register and unregister with your service. To call back on to the registered clients, use beginBroadcast(), getBroadcastItem(int), and finishBroadcast().
Broadcast sample:
int i = callbacks.beginBroadcast();
while (i > 0) {
i--;
try {
callbacks.getBroadcastItem(i).somethingHappened();
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
callbacks.finishBroadcast();
The code you show is for binding to a service. You do not show where you are registering a listener with that service. You apparently are, based upon your question and your reference to an onResult() method. Given the nature of your problem, I am going to guess that what you're doing is:
Binding to the service in onCreate()
In onServiceConnected(), you are calling some sort of setListener() method on the Binder
In that case, if we ignore configuration changes, the proper way to unwind matters would be to, in onDestroy(), call some removeListener() method on the Binder, then call unbindService().
Configuration changes, particularly in a pre-fragment world, make this complicated. It's the reason why this sample project (and the accompanying material in the book) is so icky. Binding is twitchy -- if you unbind from the old activity, and nothing else is keeping the service around, the service will shut down before the new activity gets a chance to bind. Binding is also state -- you cannot simply fail to unbind, lest you leak stuff.
So, the recipe becomes:
Bind to the service in onCreate() using the Application Context
In onServiceConnected(), call sort of setListener() method on the Binder
In onRetainNonConfigurationInstance(), make note of the fact that you're undergoing a configuration change, and return some Object that has your Binder, your Listener, and all the rest of your state
In onCreate(), use getLastNonConfigurationInstance() -- if it is null, proceed as normal, but if it is not null, hold onto that Binder and Listener and don't re-bind and re-register the listener
In onDestroy(), if the flag from Step #3 above is false (i.e., we are not undergoing a configuration change), call some removeListener() method on the Binder, then call unbindService().
Using fragments with setRetainInstance(true) can probably simplify this some, though I have not worked through a sample for that yet.
I had this issue too. You need to release all the resources,listeners,threads from the service when it finishes.
Your activity has to register/unregister itself as the listener. You need to use the proper lifecycle callback methods, not onBackPressed(). Register onStart(), unregister onStop(). One way to do it is to make the listener a static member of your service, and provide static register/unregister methods. Then call those from your activity as appropriate.
I finally solved the issue (and no, I haven't been working on it for so long :D).
The callback to the listener was made before the Fragment's onDestroy was called. So the boolean "dontupdate" value was never set to false. Overriding onBackPressed in the main activity solved the problem, as I invoked a destroy() method for each fragment that takes care of setting the boolean value to false.

Categories

Resources