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.
Related
I am developing an application in which i am getting white screen before splash screen when ever i run the app.
On splash screen i created database in background also i am having the push notification registration code. For push notification registration i refer this link. So my code of splash screen code is as follows:
public class SplashScreenActivity extends AppCompatActivity {
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private BroadcastReceiver mRegistrationBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
mRegistrationBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean sentToken = sharedPreferences.getBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false);
if (sentToken) {
// TODO token sent to server
} else {
// TODO show error that token not sent to server
}
}
};
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
InitializeScreen();
}
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i("Splash screen activity", "This device is not supported.");
finish();
}
return false;
}
return true;
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, new IntentFilter(QuickstartPreferences.REGISTRATION_COMPLETE));
}
private void InitializeScreen() {
new LoadDataBase(SplashScreenActivity.this).execute(SplashScreenActivity.this);
}
private class LoadDataBase extends AsyncTask<Context, Void, Void> {
Context context;
public LoadDataBase(Context context){
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Context... arg0) {
// Create data base from assets folder.
DatabaseHelper databaseHelper = new DatabaseHelper(arg0[0]);
try {
databaseHelper.createDataBase();
} catch (IOException e) {
e.printStackTrace();
}
// Closing the Data base.
databaseHelper.close();
return null;
}
#Override
protected void onPostExecute(Void result) {
pauseSplashScreen(context);
}
}
public void pauseSplashScreen(final Context context) {
// New Thread call.
new Thread() {
// Running Thread.
public void run() {
int count = 0;
while (count < 5) {
try {
Thread.sleep(1000);
} catch (Throwable e) {
e.printStackTrace();
}
count++;
}
Intent intent = new Intent(context, Activity2.class);
startActivity(intent);
finish();
}
}.start();
}
}
The issue is : I am getting white screen at app start before splash screen and may be that is due to push notification registration given in above link.
What should i do to avoid that white screen. Please guide me.
You are using a private inner class to create the database. And from there you call pauseSplashScreen(context). That then starts a new thread? Why?
I recommend giving the async task it's own class with a interface to give a signal back to your calling activity.
if you use
Intent intent = new Intent(context, Activity2.class);
startActivity(intent);
You don't have to call finish(), that call is better used to finish the current activity and get back to the previous one. (I get you use a thread to not block the rest of you app running, is it not better to let that thread get back to you, and then move to the next Activity?)
So, to answer your question, my guess is that the startup of your Activity takes some time, and what you see is a blanc layout loaded.
It's just because you are using the debug version, when you change to the release version, it will be gone don't wry about it!
I have a single Activity and one Service. The activity is used for search and the service is used to display a hovering widget over all the screens like Facebook chat head does.
When the user leaves the activity like pressing back key I start a service and the widget starts hovering. On Clicking the hovering widget the activity is again relaunched from service by using FLAG_ACTIVITY_NEW_TASK. But doing this when my activity is overlapped by other app activity neither onStop() nor onPause() is getting called. onStop() is called when the activity on top of it onStop() is called.
Can someone explain why this is happening? Thanks in advance.
Activity Code:
public class CouponSearchActivity extends AppCompatActivity {
public static final String TAG = CouponSearchActivity.class.getSimpleName();
public static final String BROADCAST_ACTION_ACTIVITY_STARTED =
"activity_created";
public static final String BROADCAST_ACTION_ACTIVITY_STOPPED = "activity_stopped";
public static void startActivity(Context context){
Intent intent = new Intent(context, CouponSearchActivity.class);
context.startActivity(intent);
}
public static void startActivityFromService(Context context){
Intent intent = new Intent(context, CouponSearchActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("TAG",": onCreate()");
setContentView(R.layout.activity_coupon_search);
CouponWidgetService.stopService(this);
if(savedInstanceState == null){
initCouponSearchFragment();
}
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("TAG",": onNewIntent()");
}
private void initCouponSearchFragment(){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, CouponSearchFragment.newInstance()).commit();
}
private void sendBroadcast(){
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION_ACTIVITY_STARTED);
sendBroadcast(intent);
Log.d("Broadcast sent", action = " +BROADCAST_ACTION_ACTIVITY_STARTED);
}
#Override
protected void onResume() {
super.onResume();
Log.d("TAG","onResume()");
sendBroadcast();
CouponWidgetService.stopService(this);
}
#Override
protected void onPause() {
super.onPause();
Log.d("TAG + "onPause()");
}
#Override
protected void onStop() {
super.onStop();
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION_ACTIVITY_STOPPED);
sendBroadcast(intent);
Log.d("TAG", "onStop()");
Log.d("Broadcast sent", action = " + BROADCAST_ACTION_ACTIVITY_STOPPED);
CouponWidgetService.startService(this, StoreCoupons.getStoreCouponsResponse(), StoreCoupons.getSelectedCategories());
}
#Override
public void onBackPressed() {
Log.d("onBackPressed()");
//CouponWidgetService.startService(this, StoreCoupons.getStoreCouponsResponse(), StoreCoupons.getSelectedCategories());
super.onBackPressed();
}
But doing this when my activity is overlapped by other app activity
neither onStop() nor onPause() is getting called.
This looks like a legit behavior to me. When your Activity is overlapped by some other Activity, onPause will be called. If the "overlap" is complete (i.e. your Activity is no longer visible), then its onStop should also be called.
At some later time, when you click on "hovering widget", your Activity is already paused (and, potentially, stopped), therefore it won't get those lifecycle callbacks again.
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..
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();
}
});