How to log crash reports in Production build from 1 place - android

I found this answer, It helped me a lot in understanding the scenario. But, what if i have 100 Activities in my application, and crash can happen in any of them, Is there a possibility that I log all crashes from 1 single place, instead of writing this code in every single activity.
I want to save the stacktrace in some file, whenever a crash happen in application, and i want to do this globally, not by going into each activity.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Sets the default uncaught exception handler. This handler is invoked
// in case any Thread dies due to an unhandled exception.
Thread.setDefaultUncaughtExceptionHandler(new CustomizedExceptionHandler(
"/mnt/sdcard/"))
;

You can do that in your Application class.
public class MyDemoApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
if (!BuildConfig.DEBUG) {
Thread.setDefaultUncaughtExceptionHandler( <YOUR_CUSTOM_EXCEPTION_HANDLER> );
}
}
}

Related

android: Handle Application Crash and start a particular Activity

I have an app and if the app crashes in a particular activity, it restarts at one of the intermediate parent activities.
This is a problem for me since I have some inputted user info that is lost upon crash.
Is there any way to force the app to start from the launcher screen after restarting from a crash?
Thanks.
Proposed Solution 1 -
Add this tag android:clearTaskOnLaunch="true" in the manifest.xml file to your main activity which should always launch.
Probable Reason why it did not work
When the application crashes, it throws an Exception and we need to handle the Exception and otherwise we would not get the expected behavior
Proposed Solution 2
Try to handle any uncaught Exception and tell the system what to do. To implement this, try the below steps.
Create a class extending Application Class
Handle uncaughtException in your Application subclass.
In your launcher Activity, call your Application class.
After catching an Exception, start your main Activity (as per your requirement).
Code Sample
Step 1 and 2
package com.casestudy.intentsandfilter;
import android.app.Application;
import android.content.Intent;
public class MyApplication extends Application
{
#Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException (Thread thread, Throwable e) {
handleUncaughtException (thread, e);
}
});
}
private void handleUncaughtException (Thread thread, Throwable e) {
// The following shows what I'd like, though it won't work like this.
Intent intent = new Intent (getApplicationContext(),DrawView.class);
startActivity(intent);
// Add some code logic if needed based on your requirement
}
}
Step 3
public class MainActivity extends Activity {
protected MyApplication app;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get the application instance
app = (MyApplication)getApplication();
.............
}
}
Step 4
Modify the below method as per your requirement
private void handleUncaughtException (Thread thread, Throwable e) {
// The following shows what I'd like, though it won't work like this.
Intent intent = new Intent (getApplicationContext(), HomeActivity.class);
startActivity(intent);
// Add some code logic if needed based on your requirement
}
I would recommend using library such as
https://github.com/Ereza/CustomActivityOnCrash
As the library takes care of other stuff along with different versions of android.
First, create and set the App class in your AndroidManifest.xml and
android:name=".App"
android:clearTaskOnLaunch="true"
then put this code in the App class
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable e) {
Log.d("AppCrash", "Error just lunched ");
}
});
}}
Debug Log Screenshot:
Maybe there's no way to do that but you can flag it so you know if the activity was started through user action or if it was just started after a crash.
i.e when you start the parent activity, pass something into the startActivity intent. If that isn't there then it was started after the crash.
I managed to start my main activity with intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); like this:
private void handleUncaughtException (Thread thread, Throwable e)
{
Intent intent = new Intent (getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}

onCreate sometimes running in background

I'm not quite sure how to debug the phenomenon I'm currently seeing in my Android application.
I have an Activity which is just doing some networking stuff (which needs to be done in background).
This activity is launched from a PreferencesFragment using an Intent.
When the user selects the preference item, the Intent is fired and the Activity is started (then it does the networking stuff and quits using finish()).
I created an AsyncTask to perform the networking actions in the background.
(I thought that onCreate will most probably run in the UI thread...)
But then, an exception occurred:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Did onCreate() already run in the background???
To test that, I moved the networking functions directly into onCreate().
This was working well...
... at least several times.
Suddenly, an exception was thrown:
java.lang.RuntimeException: Unable to start activity ComponentInfo{...}: android.os.NetworkOnMainThreadException
Moving the code back to the AsyncTask helped... for some time.
Does anyone know why this phenomenon might occur?
Are there scenarios when onCreate() runs in the UI thread and others when onCreate() runs in background?
My class is as simple as this:
public class ReregisterInDb extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
new ReregisterAsyncTask().execute(""); // solution 1
// solution 2
//GCMFunctions gcmFunctions = new GCMFunctions(getApplicationContext());
//gcmFunctions.registerInDb();
super.onCreate(savedInstanceState);
finish();
}
class ReregisterAsyncTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
GCMFunctions gcmFunctions = new GCMFunctions(getApplicationContext());
gcmFunctions.registerInDb();
return null;
}
}
}
try to move the call of the method finish() of the activity in the method onPostExecute of async task
You can't do anything before calling super.onCreate(...) put that right at the beginning as I've shown below. EDIT: Also, your use of getApplicationContext in the AsyncTask is likely causing an issue, try creating a global Context variable and initializing that in onCreate and see if that works.
Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
new ReregisterAsyncTask().execute(""); // solution 1
finish();
}
class ReregisterAsyncTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
GCMFunctions gcmFunctions = new GCMFunctions(mContext);
gcmFunctions.registerInDb();
return null;
}
}
I finally found out the reason for this strange behavior.
I did not post the contents of the registerInDb() method.
In that method, there is a Toast:
Toast.makeText(context,
"Not currently registered with GCM. [...]",
Toast.LENGTH_LONG).show();
This message is causing the exceptions...
The solution is:
call the function in the UI thread so that the Toast messages work and
enter code heremove the AsyncTask to only cover the actual network code.
Sorry for not giving all the details. I did not think that the Toast message was the root cause.
I learned that you cannot have Toasts in AsyncTasks. The always have to run on the UI thread.

Android Libgdx app startes only after resinstall or reboot

The main problem is that the app starts only after installation or reboot.
Second time the application does not run correctly.
Details are below.
I have encountered with a few strange problems
1) Libgdx did not detect screen size correctly on Android 4 in
SCREEN_WIDTH = Gdx.graphics.getWidth();
I got 369*320 instead of 960*540
I do as follows to fight with this problem:
I run main Activity class, where I get screen size using Display
Then I run AndroidApplication class where I start Admob and Libgdx class.
2) The second problem is that the app starts
with no initialized values, that is to say with the same memory.
No initialization of values such as boolean abc=false;
Looks like invalid exit?
In Libgdx class (third class) I set some value exit=true and exit,
disposing all textures. Program returns to the second class .
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Data.exit) finish();
Second class returns to main activity
which checks exit in the same manner
3) Next interesting thing is that now Gdx.graphics.getWidth()
gets screen size correctly. Mistery...
4) If so, I remade the app.
And now main class starts Libgdx class.
It works and exits good, but only first time after installation or reboot.
Seconds time Libgdx onCreate starts, but render() does not.
Looks like invalid exit after first start again:
The main class code is here
public class MyActivity extends AndroidApplication
implements IActivityRequestHandler {
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
context.startService(new Intent(context, BillingService.class));
....
// Create the libgdx View
View gameView = initializeForView(new MyGame(this), false);
// Create and setup the AdMob view
adView = new AdView(this, AdSize.BANNER, "aaaaaaa");
}
#Override
public synchronized void onPause() {
super.onPause();
}
#Override
public void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
Any ideas? Thanks!!
You are using statics. They preserve their value when you close the app, and you open it again before Android destroys the process, hence using the same VM. You cannot control when Android will destroy it, so try to initialize these variables in the constructor/create method of their class.
Instead of:
static boolean abc=false;
Use:
static boolean abc;
public MyClass/create(){
abc=false;
}
Or do not use statics unless necessary.

How do I start another activity from UncaughtExceptionHandler.uncaughtException() method? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Using global exception handling with “setUncaughtExceptionHandler” and “Toast”
I have implemented UncaughtExceptionHandler in onCreate() in one of my activities.
In uncaughtException() method I am trying to open another activity ErrorActivity with an extra parameter (error msg and stacktrace). That activity should only show (ment globaly) AlertDialog and handle logs etc.
Can some one tell me why the ErrorActivity doesnt open while the code in oncoughtException gets executed? I suspect the problem is Thread related.
Here is my first activity (simulating exception in onCreate())
public class MainActivity extends Activity {
GlobalSettings settings;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.currentThread().setUncaughtExceptionHandler(
new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Intent intent = new Intent(MainActivity.this,
ErrorActivity.class);
Bundle bundle = new Bundle();
bundle.putString("ERROR", ex.getMessage());
intent.putExtras(bundle);
startActivity(intent);
}
} );
settings = (GlobalSettings) getApplication();
settings = null;
settings.getApplicationContext();
setContentView(R.layout.main);
}
}
And my second activity that should handle errors:
public class ErrorActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
String name = bundle.getString("ERROR");
ShowAlertDialog(name);
}
}
You can add attribute android:process=":report_process" to the <activity> element which refers to your bug report activity in AndroidManifest.xml.
By default, activities belong to the same appliction would run in the same process identified by your package name. By setting android:process attribute, you can override this. android:process starting with : refers to a private identifier within your package, so that you can start the activity in a new process without conflicting other packages' process.
Refer Using global exception handling with “setUncaughtExceptionHandler” and “Toast”
There Qberticus told
You're not seeing anything because the
exception happened on your UI thread
and the stack unrolled all the way. So
there is no more Looper and there is
no support there that is used to
display the Toast.
Since the exception happens on UI we cannot do an UI operation :(

Android AsyncTask context behavior

I've been working with AsyncTasks in Android and I am dealing with an issue.
Take a simple example, an Activity with one AsyncTask. The task on the background does not do anything spectacular, it just sleeps for 8 seconds.
At the end of the AsyncTask in the onPostExecute() method I am just setting a button visibility status to View.VISIBLE, only to verify my results.
Now, this works great until the user decides to change his phones orientation while the AsyncTask is working (within the 8 second sleep window).
I understand the Android activity life cycle and I know the activity gets destroyed and recreated.
This is where the problem comes in. The AsyncTask is referring to a button and apparently holds a reference to the context that started the AsyncTask in the first place.
I would expect, that this old context (since the user caused an orientation change) to either become null and the AsyncTask to throw an NPE for the reference to the button it is trying to make visible.
Instead, no NPE is thrown, the AsyncTask thinks that the button reference is not null, sets it to visible. The result? Nothing is happening on the screen!
Update: I have tackled this by keeping a WeakReference to the activity and switching when a configuration change happens. This is cumbersome.
Here's the code:
public class Main extends Activity {
private Button mButton = null;
private Button mTestButton = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mButton = (Button) findViewById(R.id.btnStart);
mButton.setOnClickListener(new OnClickListener () {
#Override
public void onClick(View v) {
new taskDoSomething().execute(0l);
}
});
mTestButton = (Button) findViewById(R.id.btnTest);
}
private class TaskDoSomething extends AsyncTask<Long, Integer, Integer>
{
#Override
protected Integer doInBackground(Long... params) {
Log.i("LOGGER", "Starting...");
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 0;
}
#Override
protected void onPostExecute(Integer result) {
Log.i("LOGGER", "...Done");
mTestButton.setVisibility(View.VISIBLE);
}
}
}
Try executing it and while the AsyncTask is working change your phones orientation.
AsyncTask is not designed to be reused once an Activity has been torn down and restarted. The internal Handler object becomes stale, just like you stated. In the Shelves example by Romain Guy, he simple cancels any currently running AsyncTask's and then restarts new ones post-orientation change.
It is possible to hand off your Thread to the new Activity, but it adds a lot of plumbing. There is no generally agreed on way to do this, but you can read about my method here : http://foo.jasonhudgins.com/2010/03/simple-progressbar-tutorial.html
If you only need a context and won't use it for ui stuff you can simply pass the ApplicationContext to your AsyncTask.You often need the context for system resources, for example.
Don't try to update the UI from an AsyncTask and try to avoid handling configuration changes yourself as it can get messy. In order to update the UI you could register a Broadcast receiver and send a Broadcast.
You should also have the AsyncTask as a separate public class from the activity as mentioned above, it makes testing a lot easier. Unfortunately Android programming often reinforces bad practices and the official examples are not helping.
This is the type of thing that leads me to always prevent my Activity from being destroyed/recreated on orientation change.
To do so add this to your <Activity> tag in your manifest file:
android:configChanges="orientation|keyboardHidden"
And override onConfigurationChanged in your Activity class:
#Override
public void onConfigurationChanged(final Configuration newConfig)
{
// Ignore orientation change to keep activity from restarting
super.onConfigurationChanged(newConfig);
}
To avoid this you can use the answer givin here: https://stackoverflow.com/a/2124731/327011
But if you need to destroy the activity (different layouts for portrait and landscape) you can make the AsyncTask a public class (Read here why it shouldn't be private Android: AsyncTask recommendations: private class or public class?) and then create a method setActivity to set the reference to the current activity whenever it is destroyed/created.
You can see an example here: Android AsyncTask in external class

Categories

Resources