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 :(
Related
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> );
}
}
}
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);
}
If FirstActivity is the root of the task, and it finishes itself and launches SecondActivity, then calling isTaskRoot() in SecondActivity immediately will return false, because the FirstActivity's finishing happens asynchronously and thus isn't done yet. Waiting for a second and then calling isTaskRoot() returns true.
public class FirstActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finish();
startActivity(new Intent(this, SecondActivity.class));
}
}
public class SecondActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onResume() {
super.onResume();
((TextView)findViewById(R.id.tv1))
.setText("isTaskRoot() in onResume(): " + isTaskRoot());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
((TextView)findViewById(R.id.tv2))
.setText("isTaskRoot() after 1s: " + isTaskRoot());
}
}, 1000);
}
}
Is there a way to …
(optimally) find out whether the activity will be the task root eventually, or,
(better than nothing) get some sort of notification/callback once the task is in its "final" state and thus isTaskRoot() will return the "truth"?
I've had a similar problem and I wanted tight control over exactly who the root activity is. In my case, the root could only be one of my own activities (not 3rd party ones), so I was able to use the following approach:
I extended the Application class, added a weak reference to an activity called currentRootActivity and added synchronized getter and setter.
Then I managed this state by myself when activities were created / destroyed. My use case was a little special because I was looking to replace one root with another, so I knew exactly where to reset my new state variable, but I'm pretty sure you can do the same.
I was even able to add this state logic in a shared base class for all of my activities. So this wasn't as disgusting as it sounds :)
As mentioned in the comments, the activity method isFinishing might also come in handy.
Try:
Intent intent = new Intent(this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
I expect that this will make SecondActivity the root activity.
I have 3 screens in my app, each of which are in their own classes. When the app launches, my Driver class sets up some GUI elements, and then launches the first Intent.
I have a separate GUI class (which Driver invokes) which handles everything from menu's to dialog boxes. Previously my app didn't use Intents so I could pass the activity/context from Driver to Gui in its constructor as an object of type Activity and as a result could define layouts etc like LinearLayout ll = new LinearLayout(activity) and everything would be operating in the same activity/context.
Since I've moved to using intents, each Activity/Class has its own context, thus the previous dialogs and popup boxes from the Gui class are in the background and not running. I get an error saying android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy#406629a0 is not valid; is your activity running? when I click on a button to launch a dialog.
To me, this indicates the new Intents have taken over the foreground and the objects from the previous context are out of scope.
So, is there a way I can still pass the same context through to the new Intents so I can still access these shared dialogs? Or will I have to bring the code into each class (duplicate code)?
In case thats a bit hard to understand, here is some basic source code:
public class Driver extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Gui display = new Gui(this);
display.showScreen();
}
}
/////////////GUI.java///////////////////////
public class Gui
{
private Activity activity;
private Gui()
{}
public Gui(Activity _activity)//,Context _context)
{
this();
activity = _activity;
}
public void showScreen()
{
if(isLocationMode())
{
Intent i = new Intent(activity,LocationScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//locatScreen = new LocationScreen(activity);
//mainLayout.addView(locatScreen.getView());
}
else if (isManageMode())
{
Intent i = new Intent(activity,ManageScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//manageScreen = new ManageScreen(activity);
//mainLayout.addView(manageScreen.getView());
}
else if (isForwardMode())
{
Intent i = new Intent(activity,ForwardScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//forwardScreen = new ForwardScreen(activity);
//mainLayout.addView(forwardScreen.getView());
}
}
}
Have a setContext(Activity _activity) method in your Gui and call this in the onCreate of each activity?
I am in one activity say Activity A. I am calling another activity B.
In activity A I write the following Statement:
startActivity(new Intent(this,ActivityB.class));
Now, I want to log a debug message only when Activity A is able to successfully launch ActivityB.
How can I achieve this feature in Android.
Any kind of Help is appreciated
Thanks,
You can use the startActivityForResult method to achieve this. Use this in your Activity "A"
Or else if thats not what you are looking for, I am guessing you want to log when activity B starts and stos. Activity class provides lifecycle methods for start, stop, pause resume, etc.
Override them and put your logging code in there:
public class B extends Activity {
private static final String TAG = "B-Activity";
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "Activity created"); // or Log.d for debug
}
#Override
public void onStart() {
Log.i(TAG, "Activity started"); // or Log.d for debug
}
}