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;
}
}
Related
Android will kill some service when memory is not enough.
Like this:
I know I can use foreground service to prohibit android to kill my service
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
try {
Notification notification = new Notification(R.mipmap.ic_launcher,"this is service", System.currentTimeMillis());
Intent intent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,intent , 0);
notification.setLatestEventInfo(this, "myapp", "myservice", contentIntent);
notification.flags =Notification.FLAG_AUTO_CANCEL;
startForeground(123,notification);
}
catch(Exception e)
{
stopSelf();
}
}
#Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
But this will display a notification on screen
I would rather kill service than display notification, but I also don't want to display stopped message.
I found some app, it can display no message when android kills it.
e.g. Screen Dimmer
How can I prohibit android to display app stopped message?
Check this: https://stackoverflow.com/a/32229266/2965799
According to that I have used the following code to handle the exception. I wanted to display another message so I added my own message however if you use his answer there will be no messages.
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
new Thread() {
#Override
public void run() {
Looper.prepare();
Toast.makeText(getActivity(),"Your message", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
try
{
Thread.sleep(4000); // Let the Toast display before app will get shutdown
}
catch (InterruptedException e) { }
System.exit(2);
}
});
One way is to implement a UncaughtExceptionHandler with your own custom failure code. The API to install your handler is this:
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh);
The class is documented here. As a very basic example:
import java.lang.Thread.UncaughtExceptionHandler;
public final class CrashHandler implements UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
android.util.Log.wtf("My app name", "Oops, caught it dying on me!");
}
}
A full working example is available here.
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.
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();
I need to call the Google activity recognition service through a service (not activity) and run it in the background, of course when the user starts the app, which has an activity (But the service does not called directly from activity).
Therefore I have created a service class (ActivitySensor) and another class (ActivityRecognitionScan).
When I install the app on my Galaxy Nexus S device, the service starts calling onCreate and onDestroy automatically. Even without doing anything in the GUI
It is very strange behaviour. Does anybody has the same experience or solution for it?
I mean I get something as follows in the debug console:
Activity-Logging --- onCreate
Activity-Logging --- onDestroy
Activity-Logging --- onCreate
Activity-Logging --- onDestroy
Activity-Logging --- onCreate
Activity-Logging --- onDestroy
...
Here are my two classes:
public class ActivitySensor extends IntentService {
private ActivityRecognitionScan myascan;
private Intent inIntent;
private static long ACTIVITY_LOG_INTERVAL = 30000L;
private static JsonEncodeDecode jsonencoder = new JsonEncodeDecode();
public ActivitySensor() {
super("ActivitySensor");
}
#Override
public void onCreate(){
super.onCreate();
Log.d("Activity-Logging", "--- onCreate");
try {
myascan = new ActivityRecognitionScan(getApplicationContext());
myascan.startActivityRecognitionScan();
} catch (Exception e) {
Log.e("[Activity-Logging]","----------Error:"+e.getLocalizedMessage());
e.printStackTrace();
}
}
#Override
public void readSensor() {
// Log.e("Activity-Logging", "ActivityRecognitionResult.hasResult: "+String.valueOf(ActivityRecognitionResult.hasResult(inIntent)));
if (ActivityRecognitionResult.hasResult(inIntent)) {
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(inIntent);
DetectedActivity activity = result.getMostProbableActivity();
final int type = activity.getType();
String strType = new String();
switch(type){
case DetectedActivity.IN_VEHICLE:
strType = "invehicle";
break;
case DetectedActivity.ON_BICYCLE:
strType ="onbicycle";
break;
case DetectedActivity.ON_FOOT:
strType = "onfoot";
break;
case DetectedActivity.STILL:
strType = "still";
break;
case DetectedActivity.TILTING:
strType ="tilting";
break;
case DetectedActivity.UNKNOWN:
strType ="unknown";
break;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
Editor edt = prefs.edit();
String previousActv = prefs.getString("PREVIOUS_ACTIVIY","");
long previousDate = prefs.getLong("PREVIOUS_DATE", 0);
if (previousActv.length()==0){ // nothing was in the string and it is the first time just initialize
previousActv = strType;
previousDate = new Date().getTime();
// Log.e("-----FIRST TIME: type:", previousActv+" date:"+String.valueOf(previousDate));
edt.putString("PREVIOUS_ACTIVIY", strType);
edt.putLong("PREVIOUS_DATE", previousDate);
edt.commit();
}else {
if (!strType.equalsIgnoreCase(previousActv)){
Date readablePrevDate = new Date(previousDate);
Date nowDate = new Date();
String jsonstr = jsonencoder.EncodeActivity("Activity", readablePrevDate, nowDate, strType, activity.getConfidence());
// Log.e("[Activity-Logging] ----->",jsonstr);
edt.putString("PREVIOUS_ACTIVIY", strType);
edt.putLong("PREVIOUS_DATE", nowDate.getTime());
edt.commit();
DataAcquisitor.dataBuff.add(jsonstr);
}
}
}
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("Activity-Logging", "--- onHandleIntent"+ "---"+intent.getAction());
intent.putExtra("LOG_INTERVAL",ACTIVITY_LOG_INTERVAL );
intent.putExtra("STOP",false);
inIntent = intent;
readSensor();
}
#Override
public void onDestroy(){
Log.d("Activity-Logging", "--- onDestroy");
myascan.stopActivityRecognitionScan();
myascan=null;
//super.onDestroy();
}
}
This is the class that calls the Google Activity Recognition Service:
ActivityRecognitionScan implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener {
private Context ctx;
private static final String TAG = "ActivityRecognition";
private static ActivityRecognitionClient actrecClient;
private static PendingIntent callbackIntent;
private long ACTIVITY_LOG_INTERVAL=30000;
public ActivityRecognitionScan(Context context) {
ctx=context;
}
public void startActivityRecognitionScan(){
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(ctx);
if(resp == ConnectionResult.SUCCESS){
actrecClient = new ActivityRecognitionClient(ctx, this, this);
if (!actrecClient.isConnected()){
actrecClient.connect();
} else{
Log.e("ActivityRecognitionScan"," ---Activity recognition client is already connected");
}
}else{
Log.e("[Activity-Logging]", "Google Play Service hasn't installed");
}
}
public void stopActivityRecognitionScan(){
try{
if (actrecClient.isConnected() || actrecClient.isConnecting() ){
actrecClient.removeActivityUpdates(callbackIntent);
actrecClient.disconnect();
}
} catch (Exception e){
e.printStackTrace();
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.e("[ActivityRecognitionScan]", "Connection Failed");
}
#Override
public void onConnected(Bundle connectionHint) {
try{
Intent intent = new Intent(ctx, ActivitySensor.class);
Bundle bundle = intent.getExtras();
callbackIntent = PendingIntent.getService(ctx, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long interval = 5000;
if ( null!= bundle && bundle.containsKey("LOG_INTERVAL") ){
interval = bundle.getLong("LOG_INTERVAL");
}
actrecClient.requestActivityUpdates(interval, callbackIntent);
actrecClient.disconnect();
}catch(Exception ex){
Log.e("[Activity-Logging]","Error in requesting Activity update "+ex.getMessage());
ex.printStackTrace();
}
}
#Override
public void onDisconnected() {
callbackIntent.cancel();
actrecClient = null;
Log.e("[ActivityRecognitionScan]","---onDisconnected");
}
}
IntentService automatically stops itself on completion of onHandleIntent as per the source code (see ServiceHandler.handleMessage()) as per the description of an IntentService:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Use a Service if you want it to run continuously in the background.
You have 2 issues with your code that is causing the problem you are experiencing.
When activity is detected, the pending intent that is called calls (and creates, since it is an IntentService) ActivitySensor. The onCreate will connect another ActivityRecognitionClient, which is unnecessary. This causes another activity to be detected which causes your logging loop.
You should separate the creation of the ActivityRecognitionClient from the handling of the detected activity. You don't need to keep recreating it as subsequent detections will use the same PendingIntent. This will prevent the logging loop.
Is there a way for my to program my app to automatically restart itself whenever it crashes? My app is just a simple media rendering App, however it occasionally crashes ( it's supposed to ). Is this at all possible? Thanks. My code looks like this
public void Play(){ if(mp != null) {
mp.reset();
mp.release();
mp = null;
}
AudioRenderer mr = new AudioRenderer();
mp = mr.AudioRenderer(filePath);
}
private class AudioRenderer extends Activity {
private MediaPlayer AudioRenderer(String filePath) {
File location = new File(filePath);
Uri path = Uri.fromFile(location);
mp= MediaPlayer.create(this, path);
}
return mp
}
this will do the job for you.
How to start the automatically stopped android service?
still i don't understand why it is supposed to crash.
UPDATE
you create an handler for uncaught exception
private Thread.UncaughtExceptionHandler onRuntimeError= new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable ex) {
//Try starting the Activity again
};
in your on create, you register an handler for uncaught exception
#Override
protected void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(onRuntimeError);
}
I might be late a lot, but I found 2 in 1 solution for your problem.
public void doRestart() {
Intent mStartActivity = new Intent(context, LoginActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
}
private void appInitialization() {
defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(_unCaughtExceptionHandler);
}
//make crash report on ex.stackreport
private Thread.UncaughtExceptionHandler defaultUEH;
// handler listener
private Thread.UncaughtExceptionHandler _unCaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
ex.printStackTrace();
doRestart();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_index);
appInitialization();