I tried to start an activity with an implicit intent after an uncaught exception with the unCaughtExceptionHandler. The intent should start an Activity as a Dialog in the same app that has crashed. This corresponds to the example listed in this thread:
Need to handle uncaught exception and send log file
I call the original unCaughtExceptionHandler at the end of my own handler procedure, like this:
public class ThisApplication extends Application
{
Thread.UncaughtExceptionHandler originalUncaughtExceptionHandler;
#Override
public void onCreate ()
{
originalUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException (Thread thread, Throwable e)
{
handleUncaughtException (thread, e);
}
});
super.onCreate();
}
public void handleUncaughtException (Thread thread, Throwable e)
{
e.printStackTrace();
Intent intent = new Intent ();
intent.setAction ("de.mydomain.myapp.action.PROCESS_LOG");
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
if (intent.resolveActivity(getPackageManager()) == null) {
Log.d("ThisApplication","No receiver");
} else {
Log.d("ThisApplication", "Intent start");
startActivity(intent);
}
originalUncaughtExceptionHandler.uncaughtException(thread, e);
}
}
The result is, that after an Exception the standard Dialog is displayed that says something like "Unfortunately App xxx was closed". Behind that Dialog, in the background, I can see my Dialog that should be started with this intent "PROCESS_LOG". So obviously is was started, but the problem is, that after the standard Dialog has been closed, my custom dialog also closes. If I add
android:launchMode="singleInstance"
in the manifest of the dialog activity, the dialog is hidden, too, but it can be activated again when the app is selected from the recent apps menu. This seems to me as if the dialog is not started fully independently from the former app process/task.
Can somebody say what I did wrong?
This is the manifest part of the dialog activity:
<activity
android:name=".ProcessLogActivity"
android:windowSoftInputMode="stateHidden"
android:theme="#style/ProcessLogActivity"
android:process=":report_process"
>
<intent-filter>
<action android:name="de.mydomain.myapp.action.PROCESS_LOG" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The corresponding style:
<style name="ProcessLogActivity" parent="#style/Theme.AppCompat.Light.Dialog">
</style>
This is the Dialog Activity class:
public class ProcessLogActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature (Window.FEATURE_NO_TITLE);
setFinishOnTouchOutside (false);
Log.d("ThisApplication", "Intent received");
setContentView(R.layout.activity_process_log);
}
}
To post a full message (comment is too short), here the full class and configuration:
I tried to use ACRA with the built-in dialog-functionality, but I could not get it work. But the built-in funtionality to show a "Toast" works! So that's why I ask myself where the problem is showing the dialog. I use the following #ReportCrashed Annotation for testing:
#ReportsCrashes(
formUri = "http://yourserver.com/yourscript",
mode = ReportingInteractionMode.NOTIFICATION,
resDialogText = R.string.app_name,
resNotifTickerText = R.string.app_name,
resNotifTitle = R.string.app_name,
resNotifText = R.string.app_name
)
Inside my own Application-Class I use the following initialisation:
public class ThisApplication extends Application {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(this);
configurationBuilder.setBuildConfigClass(BuildConfig.class);
final ACRAConfiguration config;
try {
config = configurationBuilder.build();
ACRA.init(this, config);
} catch (ACRAConfigurationException e) {
e.printStackTrace();
}
}
}
My App uses two different Build flavors and the two build types "Debug" and "Release".
When I throw an unhandled exception the app closes and a dialog is only sometimes displayed for a very short moment (less than half a second) before the whole app is closed without any dialog.
Any ideas?...
EDIT: The above Annotation was the try with a Notification, that also does not work. The notification is also displayed only for a very short moment and then disappears immediately. The dialog Annotation was:
#ReportsCrashes(
formUri = "http://yourserver.com/yourscript",
mode = ReportingInteractionMode.DIALOG,
resDialogText = R.string.app_name
)
This has the effect described above.
The Problem was - at least in the case of the ACRA-Dialog - that it is not working as the app is debugged with the built-in functionality from android studio. So you have to start the app on the android test system (on the debugging device) without support from android studio IDE. When you do that and an exception is thrown, the ACRA-Dialog appears as it should.
Related
I have a pretty straight forward setting, setup
my intent filters for my main activity on the manifest
singleTask mode for all my activities (it just have two)
My app have two entry points: one the intent filter will call my MainActivity which start the branch session return the values on the referringParams and I go to the SecondActivity, everyone is happy
the another entry point is the launcher, when I click open the MainActivity do somethhing different because intent.data is empty and Go to SecondActivity, the problem is as follows, after the app is in the SecondActivity and the app goes background (e.g. touch home button) and then tap on some link the MainActivity is launched intent.data is not empty there's a valid url but when my callback is called I got referringParams empty {}
I dont know what is wrong with this. i have spend some hours without success
#Override
public void onStart() {
super.onStart();
Branch branch = Branch.getInstance();
branch.initSession(new Branch.BranchReferralInitListener(){
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
if (error == null) {
// here referringParams is a empty {} object
} else {
Log.i("MyApp", error.getMessage());
}
}
}, this.getIntent().getData(), this);
}
#Override
public void onNewIntent(Intent intent) {
this.setIntent(intent);
}
I am not sure what processing you are doing in your Main Activity. The use case you mentioned, should return the Branch link parameters correctly,
If you have the intent filters and the launchMode of the MainActivity, correctly defined
You are overriding the onNewIntent() method in your MainActivity (which I can see from the code snippet you shared)
I created a sample app, which is uploaded here. If you follow the test case you mentioned with this app(i.e. App is backgrounded with the SecondActivity), clicking on a Branch link returns the link parameters correctly.
I am wondering if it is possible to change the crash message for android?("unfortunately app has stopped") I haven't found anything that says you can(which I don't think you can), I am just making sure by asking on here.
Thanks
You cannot change the system message as stated by #Nuno Gomes but you can suppress the original message and display a message on your own or start some activity.
You can define an exceptionhandler that catches all uncaught exceptions in app class and show a message box from there
public class MyApp extends Application implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler mPreviousUncaughtExceptionHandler;
#Override public void onCreate() {
super.onCreate();
mPreviousUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
#Override
public void uncaughtException(Thread thread, Throwable ex) {
try {
// Do your stuff with the exception
Log.e(Global.LOG_CONTEXT,"LogCat.uncaughtException " + ex, ex);
// show user defined messagebox
} catch (Exception e) {
/* Ignore */
} finally {
// uncomment this to let Android show the default error dialog
// mPreviousUncaughtExceptionHandler.uncaughtException(thread, ex);
}
}
}
the app must be declared in the manifest
<manifest ...>
...
<application
android:name=".MyApp" ...>
</application>
</manifest>
On my android-4.4 i use this code to write a chrash log file
That message is a system message, it's outside the app scope, so no you cannot change it
I've an app that checks version compatibility at startup from within the main activity's OnCreate function. Since Android doesn't (to my knowledge) have a modal dialog, if the version is not compatible I show an AlertDialog via AlertDialog.Builder and set the neutral button action to shut down the app. Unfortunately this causes the app to restart instead of shutting down. Could someone help me get the app to shut down please?
This is being tested on Android 7.0, but also needs to run on Android 4.2.2.
public class Activity1 : FragmentActivity {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
if (!versionCheck.Success) {
ShowNotesReadonlyDialog("Version Incompatibility", versionCheck.Message, new Action(() => ShutdownApplication()) );
return;
}
}
private void ShutdownApplication() {
this.Finish();
// -- I've tried all the things below with the same result.
//this.FinishAffinity();
//this.Dispose();
//global::Android.OS.Process.KillProcess(global::Android.OS.Process.MyPid());
}
private void ShowNotesReadonlyDialog(String title, String message, Action action) {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
LayoutInflater inflater = (LayoutInflater)this.GetSystemService(Context.LayoutInflaterService);
View layout = inflater.Inflate(Resource.Layout.GenericTextViewLayout, FindViewById<ViewGroup>(Resource.Id.GenericTextViewDialogRoot));
dialog.SetTitle(title);
dialog.SetView(layout);
TextView label = layout.FindViewById<TextView>(Resource.Id.GenericTextViewMessageLabel);
label.Text = message;
dialog.SetNeutralButton("Close", (o, e) => {
if (null != action) {
action.Invoke();
}
dialog.Dispose();
});
dialog.SetCancelable(false);
AlertDialog window = dialog.Create();
WindowManagerLayoutParams p = new WindowManagerLayoutParams();
p.CopyFrom(window.Window.Attributes);
p.Width = 900;
p.Height = WindowManagerLayoutParams.WrapContent;
window.Show();
window.Window.Attributes = p;
}
}
I've placed breakpoints in several lifecycle events. After calling Finish() the following events are called on the Activity:
OnStop()
OnCreate()
OnStart()
Additionally, the Activity disappears from the screen when Finish() is called, but pressing the "window manager" hardware key shows that the application is still running. Tapping the window shows it on screen.
I made an Android APP, which has an config structure, which contains data,and services I need throughout all activities.
I now face the issue, that if my APP is in the background for a while, my APP crash, because my config structure has been deleted.
In my config structure, I also have data, I can not easily recreate at runtime.
So in my first Activity, I create the config structure.
FreightWeightConfig config = new FreightWeightConfig(getApplicationContext()); // make sure our config is up and running
And the start of my config class looks like
public FreightWeightConfig(Context appContext) {
instance = this;
mApplicationContext = appContext;
tcBlue.setCallingContext(appContext);
tcBlueConfig = Config.getInstance(); // to make sure it is available straight away
mFirebaseAuth = FirebaseAuth.getInstance();
....
}
I have a second function in the config structure, which allows me to get the instance of my config class, which I need to get access to functions and interfaces in config and services.
public static synchronized FreightWeightConfig getInstance () {
//if (FreightWeightConfig.instance == null) {
// FreightWeightConfig.instance = new FreightWeightConfig(getApplication().getApplicationContext());
//}
if (FreightWeightConfig.instance == null){
FirebaseCrash.logcat(Log.ERROR, LOG_TAG, "Fatal Error : FreightWeightConfig.getInstance()==null. Try restarting the APP");
FirebaseCrash.logcat(Log.ERROR, LOG_TAG, "Fatal Error : Killing ourself, as we have no chance to go on");
//System.exit(0); // we are in a bad state
// Toast.makeText(mApplicationContext, "Fatal Error : FreightWeightConfig.getInstance()==null. Try restarting the APP", Toast.LENGTH_SHORT).show();
}
return FreightWeightConfig.instance;
}
In every Activity, I created a variable that hold a copy the instance. This is simply, because I thought it tells the system, I still need this class, do not kill it. Which does not seem to work.
I first thought, whenever I find my config class to be dead, I can recreate it. But it is not a simple task, as I need the APP context and need to recreate my services in the background. Also I store selections made, while navigating my APP
Anyone has a good Idea, how to solve the unloading / deleting my config class?
Based on the suggestion I extended Application like this:
public class FreightWeightApp extends Application implements DialogInterface.OnCancelListener {
private String LOG_TAG = "FreightWeightApp";
private FreightWeightConfig config;
public static int GOOGLE_PLAY_SERVIE_ABBORTED = 1001;
public void onCreate() {
super.onCreate();
// We first check if the google services are present, if not, better abort!!
int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
switch (result) {
case SUCCESS:
Log.d(LOG_TAG, "Google Services available");
break;
case SERVICE_MISSING:
Log.e(LOG_TAG, "Google Services missing, STOP");
googleServiceNotUpToDateDialog(result);
break;
case SERVICE_VERSION_UPDATE_REQUIRED:
Log.w(LOG_TAG, "Service update required");
googleServiceNotUpToDateDialog(result);
break;
case SERVICE_DISABLED:
Log.e(LOG_TAG, "Service disabled, STOP");
googleServiceNotUpToDateDialog(result);
break;
}
config = new FreightWeightConfig(getApplicationContext()); // make sure our config is up and running
}
private void googleServiceNotUpToDateDialog(int result) {
// Try to ask the user to update or finish off
// GoogleApiAvailability gaa = GoogleApiAvailability.getInstance();
// Dialog dialog = gaa.getErrorDialog(this, result, GOOGLE_PLAY_SERVIE_ABBORTED, this); //<==== Can not call this, as I have no Activity Context
// dialog.show();
}
#Override
public void onCancel(DialogInterface dialogInterface) {
// Now I should abbort the APP, or we will crash.
}
}
But now I have issues with verifying the GoogleService.
Dialog dialog = gaa.getErrorDialog(this, result, GOOGLE_PLAY_SERVIE_ABBORTED, this);
as I have no Activity Context.
Create your own implementation of Application, then initialize your config object in the onCreate() method(in this case the getInstance() method could also initialize the object).
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
FreightWeightConfig config = FreightWeightConfig.getInstance(getApplicationContext());
}
}
Declare your implementation in your app's module manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="your.package">
<application
android:name="your.package.MyApplication"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
...
</application>
</manifest>
Now you can use your config instance in the activities just like you do, calling getInstance(); the Application onCreate will do the load work. But there is no way to "unload the resources before the app process gets killed/cached", you just have to understand how Android components' lifecycle works.
I have an annoying crash : I'm not even sure how to call it, my application closes without displaying any messages (0.5s black screen then desktop) and there seem not to have any RunTimeException, at least none displayed in my android console.
Intent intent = MainPagerActivity.newIntent(AuthActivity.this, mHome, mNewsFeed);
try {
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
} finally {
Log.i("renaud", " hello ");
}
//finish() //<= the bug is there with or without this
here no stacktrace's exeptions are written, my "hello" log is sent, no problem.
MainPagerActivity
#Override
public void onCreate(final Bundle savedInstanceState) {
Log.i("renaud", "hello again");
...
"hello again" is never displayed.
Note that this does not append with all my users, just one that must have something different somewhere, but nothing that I could see.
what could happend there ? Is there a step between startActivity and "onCreate" that I'm missing ?
thank you all,
Edit :
MainPagerActivity
public static Intent newIntent(Context c, HomeFeed hf, NewsFeedV2 nf) {
Intent intent = new Intent(c, MainPagerActivity.class);
intent.putExtra(HomeFeed.SERIALIZATION_NAME, hf);
intent.putExtra(NewsFeed.SERIALIZATION_NAME, nf);
return intent;
}
HomeFeed and NewsFeedV2 implements Serializable.