Hi I am dealing with a 3rd party library that is buggy at times and causes the activity restart. Is there a way to tell when an activity is restarted from a crash? I tried using an uncaught exception handler like this but it wasn't being triggered.
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable throwable) {
Log.d("un", "caught");
}
});
write like this
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this,YOURCURRENTCLASSNAME.class));
And use this class dear. i also used this
public class MyExceptionHandler implements
java.lang.Thread.UncaughtExceptionHandler {
private final Context myContext;
private final Class<?> myActivityClass;
public MyExceptionHandler(Context context, Class<?> c) {
myContext = context;
myActivityClass = c;
}
public void uncaughtException(Thread thread, Throwable exception) {
StringWriter stackTrace = new StringWriter();
exception.printStackTrace(new PrintWriter(stackTrace));
System.err.println(stackTrace);// You can use LogCat too
Intent intent = new Intent(myContext, myActivityClass);
String s = stackTrace.toString();
// you can use this String to know what caused the exception and in
// which Activity
intent.putExtra("uncaughtException",
"Exception is: " + stackTrace.toString());
intent.putExtra("stacktrace", s);
myContext.startActivity(intent);
// for restarting the Activity
// Process.killProcess(Process.myPid());
System.out.println("comingggggggggggggggggg in crashhhhhhhhhhhhhhhhhhhh and restrttttttttttttt autometically ");
Intent i = myContext.getPackageManager().getLaunchIntentForPackage(myContext.getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addCategory(Intent.CATEGORY_HOME);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
myContext.startActivity(i);
System.exit(0);
}
}
Or, if you are looking for a working-out-of-the-box solution, you can use a bug tracker service, such as Crashlytics or Crittercism. They both offer a way of knowing if the current run occurred just after a crash.
Crashlytics
Crashlytics.getInstance().setListener(new CrashlyticsListener() {
#Override
public void crashlyticsDidDetectCrashDuringPreviousExecution() {
// if this method is called, it means that a crash occurred
// in the previous run
didCrashOnLastLoad = true;
}
});
Crittercism (source)
CritterCallback cb = new CritterCallback() {
#Override public void onCritterDataReceived(CritterUserData userData) {
boolean crashedOnLastLoad = userData.crashedOnLastLoad();
// ...do something with crashedOnLastLoad
}
};
CritterUserDataRequest request = new CritterUserDataRequest(cb)
.requestDidCrashOnLastLoad();
// Fire off the request.
request.makeRequest();
Related
I want to restart my application after crash. So I created a crash handler on Application class:
public final class MyApp extends Application {
private static Thread.UncaughtExceptionHandler mDefaultUEH;
private Thread.UncaughtExceptionHandler mCaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Intent splashIntent = new Intent(getInstance().getActivity(), A1SplashScreen.class);
//splashIntent.addCategory(Intent.CATEGORY_LAUNCHER);
//splashIntent.setAction(Intent.ACTION_MAIN);
splashIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
splashIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
splashIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
int requestID = (int) System.currentTimeMillis();
PendingIntent pending = PendingIntent.getActivity(getInstance().getActivity(), requestID, splashIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getInstance().getActivity().getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis(), pending);
mDefaultUEH.uncaughtException(thread, ex);
}
};
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(mCaughtExceptionHandler);
}
}
A1SplashScreen is main activity of the application, so I want to start that activity after crash. There is no problem on API 21 and above. But problem is on API level lower than 21. After application crashes, A1SplashScreen launches but onCreate() method of it does not called. So the screen freezes and nothing shown (only white screen). It does not response and does not crash. Here is screenshot:
RESOLVED
When I call System.exit(2) method, application restarted. But I could not see crash on crashlytics. On the other hand, if I do not call System.exit(), I can see crash on crashlytic but application does not restart. That's why I ran System.exit(2) method and mDefaultUEH.uncaughtException(thread, throwable) parallel via ExecutorService. Here is the working code :
private Thread.UncaughtExceptionHandler mCaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Intent intent = new Intent(getApplicationContext(), A1SplashScreen.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
getInstance().getActivity().startActivity(intent);
activity.finish();
ExecutorService executorService = Executors.newCachedThreadPool();
CallCrashlytics callCrashlytics = new CallCrashlytics(thread, ex);
CallSystemExit callSystemExit = new CallSystemExit();
try {
executorService.invokeAll(Arrays.asList(callCrashlytics, callSystemExit));
}catch (InterruptedException e){
e.printStackTrace();
}
}
};
class CallCrashlytics implements Callable<Void>{
Thread thread;
Throwable throwable;
CallCrashlytics(Thread thread, Throwable throwable){
this.thread = thread;
this.throwable = throwable;
}
#Override
public Void call() throws Exception {
mDefaultUEH.uncaughtException(thread, throwable);
return null;
}
}
class CallSystemExit implements Callable<Void>{
#Override
public Void call() throws Exception {
System.exit(2);
return null;
}
}
Is doing all of this in one possible? I can't seem to get this to work. This is how I am catching uncaught exceptions:
public class MyApplication extends Application {
private UncaughtExceptionHandler defaultHandler;
public void onCreate() {
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 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) {
Intent crashReportIntentService = new Intent(this, SendCrashReportIntentService.class);
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
e.printStackTrace(printWriter);
String s = writer.toString();
crashReportIntentService.putExtra(SendCrashReportIntentService.STACK_TRACE, s);
startService(crashReportIntentService);
defaultHandler.uncaughtException(thread, e);// let the default handle it and crash the app
}
}
So I catch it, get the stack trace, then attempt to fire off a service. After I call startService I call defaultHandler.uncaughtException() so that the default "Unfortunately this app has crashed" message will pop up. However, it seems my service is never called.
This is what part of my service looks like:
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "***** SendCrashReportIntentService: In onHandleIntent!");
handleUncaughtException(intent.getStringExtra(STACK_TRACE));
}
I have breakpoints but this is never called and I'm getting no hits in my database.
This is a common question, and I have read up on the various ways of handling it, but each on seems to fall short for what I am trying to do, which is essentially be a good OO-Citizen.
I have an Activity that invokes a CommunicationManager, which basically polls a TCP socket for data. When the CommunicationManager receives data, it throws a custom event (containing the string it just fetched), which is handled by the Activity. I am doing this, A) because other classes will depend on that data, not just the Activity, and B) because the polling is asynchronous, and should fire an event when it receives results.
My problem lies in that I need to surface those results into a TextView on the UI. I have the polling mechanism all set up, it fires every 1000ms, and invokes the event handler on the Activity. However, the UI never updates.
Assumedly this is a thread issue and the UI thread is not the one getting the change to the TextView, but how do I do this?? I have tried using a Handler, but am not sure where to put it, and when I did get it compiling it never updated the UI.
This seems relatively trivial if everything was done within the Activity, but adding in this other class (CommunicationManager) and the event is making it very confusing for me.
Here is what I have so far:
ACTIVITY (polling is invoked by clicking a button on the UI):
public void onClick(View v) {
if (v.getId() == R.id.testUDPBtn) {
statusText.setText("");
commMgr = new CommunicationManager();
commMgr.addEventListener(this);
MediaPositionPollThread poller = new MediaPositionPollThread(commMgr);
poller.startPolling();
}
}
#Override
public void handleMediaPositionFoundEvent(MediaPositionFoundEvent e) {
statusText.append(e.userData);
}
THREAD:
class MediaPositionPollThread extends Thread {
private CommunicationManager commManager;
private static final String TAG = "MediaPositionPollThread";
private boolean isPolling = false;
public MediaPositionPollThread(CommunicationManager cm) {
commManager = cm;
}
public void startPolling() {
isPolling = true;
this.run();
}
public void stopPolling() {
isPolling = false;
}
#Override
public void run() {
while (isPolling) {
try {
commManager.getCurrentMediaPosition();
Thread.sleep(1000);
}
catch (InterruptedException e) {
Log.d(TAG, "EXCEPTION: " + e.getMessage());
}
}
}
}
COMMUNUCATION MANAGER:
public void getCurrentMediaPosition() {
PrintWriter outStream;
BufferedReader inStream;
String resultString = "";
try {
outStream = new PrintWriter(tcpSocket.getOutputStream(), true);
outStream.println("GET?current_pts");
inStream = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
resultString = inStream.readLine();
fireEventWithData(resultString);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized void addEventListener(MediaPositionFoundEventListener listener) {
_listeners.add(listener);
}
public synchronized void removeEventListener(MediaPositionFoundEventListener listener) {
_listeners.remove(listener);
}
private synchronized void fireEventWithData(String outputString) {
MediaPositionFoundEvent evt = new MediaPositionFoundEvent(this);
evt.userData = outputString;
Iterator<MediaPositionFoundEventListener> i = _listeners.iterator();
while(i.hasNext()) {
((MediaPositionFoundEventListener) i.next()).handleMediaPositionFoundEvent(evt);
}
}
So I have the Activity making a thread that gets executed every second, calling CommunicationManager >> getCurrentMediaPosition, which in turn fires the MediaPositionFoundEvent, which is handled by the Activity and updates the TextView (statusText) on the screen.
Everything works except the screen not updating. I have tried runOnUiThread, and a Handler, but am obviously not getting it right.
Thanks in advance for any insight or solutions!
In your Activity class, add a private Handler _handler,
Initialize it in your onCreate Activity method,
and change your handleMediaPositionFoundEvent method to
#Override public void handleMediaPositionFoundEvent(MediaPositionFoundEvent e) {
_handler.post(new Runnable(){
public void run(){
statusText.append(e.userData);
});
}
}
It looks like your blocking the UI thread with your custom Thread. Please update this method to call start() vs run().
public void startPolling() {
isPolling = true;
this.start();
}
I am trying to start an activity after n seconds with a handler. The application was crashing on the startActivity call, so I put the handler code in my application's onCreate, and it is still crashing (which makes me think that the error comes from me not using startActivity well) :
#Override
public void onCreate(){
String roomName = this.getSettingValue(R.string.PREFERENCES_ROOM_NAME, "");
Room room;
try {
room = this.getRoomWithName(roomName);
} catch (ReservatorException ex) {
Toast err = Toast.makeText(this, ex.getMessage(),
Toast.LENGTH_LONG);
err.show();
return;
}
Intent i = new Intent(this, RoomActivity.class);
i.putExtra("room", room);
this.startActivity(i);
}
Strange thing is that this work when called from a view, by using exactly the same code, but different context :
Intent i = new Intent(getContext(), RoomActivity.class);
// ...
I am pretty new to Android ... so there may be information missing in that question, or I might even be trying to do something completely stupid who knows ?
EDIT
Link to the stacktrace : http://pastebin.com/vh2QC3xz
EDIT2
Here is the handler version of my code (so what I am trying to do in the end) :
public class ReservatorApplication extends Application {
private GoToFavouriteRoom goToFavouriteRoomRunable;
class GoToFavouriteRoom implements Runnable {
ReservatorApplication app;
public GoToFavouriteRoom(ReservatorApplication anApp){
app = anApp;
}
#Override
public void run() {
String roomName = app.getSettingValue(R.string.PREFERENCES_ROOM_NAME, "");
Room room;
try {
room = app.getDataProxy().getRoomWithName(roomName);
} catch (ReservatorException ex) {
Toast err = Toast.makeText(app, ex.getMessage(),
Toast.LENGTH_LONG);
err.show();
return;
}
RoomActivity.startWith(app, room);
}
}
private final ReservatorAppHandler handler = new ReservatorAppHandler();
class ReservatorAppHandler extends Handler{
#Override
public void handleMessage(Message msg){
return;
}
}
#Override
public void onCreate(){
String serverAddress = getSettingValue(R.string.PREFERENCES_SERVER_ADDRESS, "mail.futurice.com");// TODO: change to mail.futurice.com before delivery
proxy = new SoapDataProxy(serverAddress);
// proxy = new DummyDataProxy();
proxy = new CachedDataProxy(proxy);
addressBook = new FumAddressBook();
try {
addressBook.prefetchEntries();
} catch (ReservatorException e) {
// TODO: DIE!
}
goToFavouriteRoomRunable = new GoToFavouriteRoom(this);
handler.postDelayed(goToFavouriteRoomRunable, 20000);
}
Ok ... I finally solved my problem, mainly thanks to #Drax
Apparently, you just can't start an activity from an application ... you need an instance of an activity. So :
public class ReservatorApplication extends Application {
#Override
public void onCreate(){
Intent i = new Intent(this, RoomActivity.class);
this.startActivity(i);
}
}
Is just not valid, and causes a RunTimeException ...
As far as crashing is concern when you start activity in handler with "this". it will take handler's context. and when you do getContext() it will take activity context.
Intent i = new Intent(YourActivityName.this, RoomActivity.class);
or
Intent i = new Intent(getBaseContext(), RoomActivity.class);
It`s hard to answer without seeing the stack trace from logcat, but I found that sometimes you need to pass the application context to the a new Intent before starting an Activity.
Try this line:
Intent i = new Intent(getApplicationContext(), RoomActivity.class);
I just want to know how to launch an Activity in a try/catch bloc, i made this
public void onReceive(Context context, Intent intent) {
SipAudioCall incomingCall = null;
try {
Intent monIntent = new Intent(this,dialog.class);
startActivity(monIntent);
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onRinging(SipAudioCall call, SipProfile caller) {
But i have errors:
constructor Intent(IncomingCallReceiver, Class<dialog>) is not defined
Method startActivity(Intent) is undefined for the type IncomingCallReceiver
I want to show an alertdialog when having a call.
How can i solve this problem?
Thank you very much.
Whole class:
public class IncomingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
SipAudioCall incomingCall = null;
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onRinging(SipAudioCall call, SipProfile caller) {
try {
call.answerCall(30);
} catch (Exception e) {
e.printStackTrace();
}
}
};
SIPCommunicator wtActivity = (SIPCommunicator) context;
incomingCall = wtActivity.manager.takeAudioCall(intent, listener);
incomingCall.answerCall(30);
incomingCall.startAudio();
incomingCall.setSpeakerMode(true);
if(incomingCall.isMuted()) {
incomingCall.toggleMute();
}
wtActivity.call = incomingCall;
wtActivity.updateStatus(incomingCall);
} catch (Exception e) {
if (incomingCall != null) {
incomingCall.close();
}
}
}
}
The problem you are facing is not the try catch block, it's the fact that you are starting activity in a listener implementation. Substitute
Intent monIntent = new Intent(this,dialog.class);
with
Intent monIntent = new Intent(<Name of this class>.this,dialog.class);
and
startActivity(monIntent);
with
<Name of this class>.this.startActivity(monIntent);
By <Name of this class> I mean the head class where you are writing your code.
By the looks of it, you are launching a new thread from within a try/catch block. This is bad practice as the thread can fail should an exception be being thrown.
Instead, declare a variable before the value, and assign to it on the line preceding the catch statement.
Also assign to it if the exception is raised, but a different value.
Then launch the thread outside the try/catch block, based on the successful evaluation of the variable.
Use callbacks to trap failed threads, not exceptions.
int x = 0;
try
{
/* Do some logic here */
x = 1; // we have success
}
catch(Exception e)
{
x = -1; // failure
}
if (x > 0)
{
Intent monIntent = new Intent(this,dialog.class);
startActivity(monIntent);
...
}
As a newbie I would like to state my view:-
Try putting some error messages to find out where the error is occurring. Also check the log file.
Example of try catch:-
try
{
//some code
//Toast message on success
Toast.makeText(this, R.string.msgStatusUpdatedSuccefully, Toast.LENGTH_LONG).show();
}
catch (TwitterException e)
{
//Toast message on failure
Toast.makeText(this, R.string.msgStatusUpdateFailed, Toast.LENGTH_LONG).show();
e.printStackTrace();
}
I would check if my imports are all fine for all the api's that I am using.
Also does your main public class looks like the following to resolve the undefined error:-
public class StatusActivity extends Activity implements OnClickListener{}