What I want to do is, close all the open activities when there is any unhandled exception.
I have a BaseActivity which is base for all the activities in my application and every activity derived from this class.
I have called setDefaultUncaughtExceptionHandler in onCreate of BaseActivity.
I have a BaseActivity as below:
public abstract class BaseActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
// Exceptions that are not handled are received in GlobalExceptionHandler class
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
}
public class MyExceptionHandler implements UncaughtExceptionHandler
{
#Override
public void uncaughtException(Thread thread, Throwable e)
{
String report = "";
// Code to generate report string
......
// Code to generate report string
// Start error screen
Intent intent = new Intent(mContext, ErrorScreen.class);
intent.putExtra("error", report);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
// Exit
System.exit(0);
}
}
}
Here is my ErrorScreen Activity:
public class ErrorScreen extends Activity implements OnClickListener
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.error_screen_layout);
// Display error report from intent
}
#Override
public void onClick(View view)
{
switch(view.getId())
{
case R.id.btn_exit_app:
{
// All this is not working
// and few activities are still there
finish();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
break;
}
}
}
On any unhandeled exception, my uncaughtException function is getting called which is as expected, then i start new activity for displaying error details and a button to exit in ErrroScreen activity.
But problem is that, after selecting exit app button, not all the activities in the application are closing, there are still few activities that are open, how to close all the open activities?
private Thread.UncaughtExceptionHandler androidDefaultUEH;
private Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable ex) {
//mInstance.startActivity(new Intent(mInstance, HomeActivity.class));
Log.e("TestApplication", "Uncaught exception is: ", ex);
// here I do logging of exception to a db
Toast.makeText(getApplicationContext(), "Something went wrong..... TimesNow App is restarting...", Toast.LENGTH_SHORT).show();
PendingIntent myActivity = PendingIntent.getActivity(getApplicationContext(),
192837, new Intent(getApplicationContext(), ToBeOpenedActivity.class),
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager;
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
15000, myActivity);
System.exit(0);
androidDefaultUEH.uncaughtException(thread, ex);
}
};
Write this method in your application class..
Related
I am working on an online radio app demo. I've created an error Activity which I want to take the user to, when an error occurs. In the error page, there is a refresh button, which is supposed to refresh the last Activity where an error occurred. But I don't know how to get the Intent of previous Activity which led to the error page to get it refresh on ButtonClick, I only know to make it return to a particular Activity.
You can use startActivityForResult in both calling activities
In MainActivity.java
int REFRESH = 1;
private void startErrorActivity() {
startActivityForResult(new Intent(this, ErrorActivity.class), REFRESH);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REFRESH) {
//do refresh
}
}
And in ErrorActivity.java
Button button = findViewById(R.id.refreshButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish(); //this will take you back to calling activities onActivityResult method
}
});
UPDATE:
I honestly think #sneharc's answer is better. Use that.
Try this:
public class ActivityA extends Activity {
public void myFunction(){
try{
// something bad happens here. need to go to ErrorActivity
}
catch (SomeException e){
Intent startErrorActivityIntent = new Intent(this, ErrorActivity.class);
startErrorActivityIntent.putExtra("sourceActivity", ActivityA.class.getSimpleName())
startActivity(this, startErrorActivityIntent)
}
}
}
public class ActivityB extends Activity {
public void myFunction(){
try{
// something bad happens here. need to go to ErrorActivity
}
catch (SomeException e){
Intent startErrorActivityIntent = new Intent(this, ErrorActivity.class);
startErrorActivityIntent.putExtra("sourceActivity", ActivityB.class.getSimpleName())
startActivity(this, startErrorActivityIntent)
}
}
}
public class ErrorActivity extends Activity {
private Intent mReceivedIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
mReceivedIntent = getIntent();
}
public void onClickRefresh(){
String retryActivityName = mReceivedIntent.getStringExtra("sourceActivity");
Intent retryActivityIntent = null;
if (!TextUtils.isEmpty(retryActivityName)){}
if (retryActivityName.equalsIgnoreCase(ActivityA.class.getSimpleName()))
retryActivityName = new Intent(this, ActivityA.class);
if (retryActivityName.equalsIgnoreCase(ActivityB.class.getSimpleName()))
retryActivityName = new Intent(this, ActivityB.class);
}
if (retryActivityIntent != null)
startActivityForResult(this, retryActivityIntent);
}
}
I have a class A which extends Application.In A i am handling uncaughtexceptions. Now the issue is whenever app encounters any issue app freezes and black screen appears before crashing
public class A extends Application {
#Override
public void onCreate() {
super.onCreate();
final AppContext context = AppContext.getInstance();
context.setContext(this);
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable e) {
mContext = context.getContext();
e.getCause().getMessage();
AppPreference.getInstance().setCrashReason(e.getMessage());
Intent intent = new Intent ();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity (intent);
System.exit(1);
}
});
}
I have searched a lot but all went in vain.Thanks in advance.
You can use the following way :
public class MyApplication extends Application
{
public void onCreate ()
{
// 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)
{
e.printStackTrace(); // not all Android versions will print the stack trace automatically
Intent intent = new Intent ();
intent.setAction ("com.mydomain.SEND_LOG");
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // required when starting from Application
startActivity (intent);
}
}
according to this answer
I'm new to Android and I'm stuck on a conception problem.
I have an application with several activities, some of those activities are critical and require the user to be logged in a webApp.
When the user clicks a button to reach one of those critical activities, I call a background Service which ask if the user is still connected to the webApp (not timeout). If the user is logged in, the activity is started, otherwise a dialog pops up and ask for username and password. The problem is that there is several protected activities, and I want to use the same service to do the verification. The way I do it for the moment works but it's kind of kludgy.
public class A_Activity extends Activity {
Context context;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getApplicationContext();
setButtonClickListener();
}
private void setButtonClickListener() {
button_1 = (Button)findViewById(R.id.button1);
button_1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intentCall = new Intent(context,com.them.cp.ConnexionManagerService.class);
intentCall.putExtra("WHO_IS_CALLED","FIRST_ACTIVITY");
context.startService(intentCall);
}
});
button_2 = (Button)findViewById(R.id.button2);
button_2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intentCall = new Intent(context,com.them.cp.ConnexionManagerService.class);
intentCall.putExtra("WHO_IS_CALLED","SECOND_ACTIVITY");
context.startService(intentCall);
}
});
}
}
And my service
public class ConnexionManagerService extends Service{
public class IsConnectedAsync extends AsyncTask<String , Void, Void>{
protected Void doInBackground(String... whoIsCalled) {
String redirectedURL = getRedirectedURL();
if(redirectedURL.equalsIgnoreCase(IF_NOT_CONNECTED_URL)){
if(whoIsCalled[0].equalsIgnoreCase("FIRST_ACTIVITY")){
Intent trueIntent = new Intent(getBaseContext(), FirstActivity.class);
trueIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(trueIntent);
}
else if(whoIsCalled[0].equalsIgnoreCase("SECOND_ACTIVITY")){
Intent trueIntent = new Intent(getBaseContext(), SecondActivity.class);
trueIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(trueIntent);
}
}
else{
Intent falseIntent = new Intent(getBaseContext(), PopUpLoginActivity.class);
falseIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(falseIntent);
}
}
return null;
}
}
#Override
public void onCreate() {
Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d("service onCreate", "onCreate");
}
public int onStartCommand(Intent intent, int flags, int startId){
String whoIsCalled = intent.getStringExtra("WHO_IS_CALLED");
new IsConnectedAsync().execute(whoIsCalled);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
with my little knowledge I wish i could just send an intent, but it seems that it's not possible as it's not the UI thread.
My question is: What can I do to make this service more generic ?
I want to use the same service to do the verification.
If you don't destroy the service it will be the same service object. If an activity which started your service finishes or stops the service it could be destroyed if it was the unique activity that started the service. If you want to ensure that the service reminds on background start it on you application class (extending Application) and in each activity you need. When an activity stops the service or finishes the service will not be destroyed because your application class is still connected.
EDIT:
To avoid write putExtra again and again:
public class StartOrder1 extends Intent {
public StartOrder(Context ctx, String activity_name){
super(ctx, ServiceName.class);
if(activity_name != null)
super.putExtra("WHO", activity_name);
else
super.putExtra("WHO", "UNKNOWN");
}
public String getWho(){
reurn.getIntExtra("WHO");
}
}
To start it:
this.startService(new StartOrder1(this, "My activity name"));
The best solution:
public class StartOrder2 extends Intent {
public StartOrder(Activity a){
super(a, ServiceName.class);
super.putExtra("WHO", a.toString());
}
public String getWho(){
reurn.getIntExtra("WHO");
}
}
And you can override toString method in each Activity passing the activity name, class name, whatever you want. Then when you start an intent:
this.startService(new StartOrder2(this));
Or extends Activity with this utility:
public class EnhancedActivity extends Activity{
protected startMyService(String name){
Intent i = new Intent(this, MyService.class);
i.putExtra("who", name);
startService(i);
}
}
And call it on your final activity
[...]
super.startMyService("activity_name");
[...]
Consider i am using five screen pages for project "A".Each page is having switching between other pages sequentially one by one,my need is to do close all the page when i am clicking the button "exit" from the page five which is the last one.
I have used this below code,but the problem is only the last page is getting close others are not.
find my code below
Button extbtn = (Button)findViewById(R.id.but_Exit);
extbtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
setResult(RESULT_OK, intent);
finish();
} });
Thanks for your time!
Make all five activities extend a BaseActivity that registers a BroadcastReceiver at onCreate (and unregisters at onDestroy).
When extbtn is clicked, send a broadcast to all those BaseActivities to close themselves
for example, in your BaseActivity add:
public static final String ACTION_KILL_COMMAND = "ACTION_KILL_COMMAND";
public static final String ACTION_KILL_DATATYPE = "content://ACTION_KILL_DATATYPE";
private KillReceiver mKillReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
...
mKillReceiver = new KillReceiver();
registerReceiver(mKillReceiver, IntentFilter.create(ACTION_KILL_COMMAND, ACTION_KILL_DATATYPE));
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mKillReceiver);
}
private final class KillReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
}
and at extbtn's onClick call:
extbtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// send a broadcast that will finish activities at the bottom of the stack
Intent killIntent = new Intent(BaseActivity.ACTION_KILL_COMMAND);
killIntent.setType(BaseActivity.ACTION_KILL_DATATYPE);
sendBroadcast(killIntent);
Intent intent = new Intent();
setResult(RESULT_OK, intent);
finish();
}
});
I am re-launching my application after my it crashes using Thread.setDefaultUncauhtExceptionHandler(). I would like to pass an intent extra telling it that it just came back from the dead, however its not sticking. Here is the onCreate of LockedUpActivity.
public class LockedUpActivity extends Activity {
/** Called when the activity is first created. */
UncaughtExceptionHandler defaultHandler;
private static final String RECOVERED = "recovered";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setDefaultHandler();
if (getIntent().getBooleanExtra(RECOVERED, false)) {
Log.i("LockedUp", "Back from the dead!");
((TextView) findViewById(R.id.textview)).setText("Back from the dead!");
}
else {
Log.i("LockedUp", "Machiavelli in this..");
}
}
public void goDownInFlames(View v) {
startActivity(new Intent(this, GoingDownActivity.class));
}
private void setDefaultHandler() {
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Intent i = new Intent(getApplicationContext(), LockedUpActivity.class);
i.putExtra(RECOVERED, true);
startActivity(i);
defaultHandler.uncaughtException(thread, ex);
}
});
}
}
As you can see, I am setting the extra, however it is never "Back from the dead!"
When an Application crashes or is 'forced stop', automatic garbage collection is done, variables are cleared, and so is the activity stack of the app. The extras won't remain there if the app crashes.