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.
Related
Im working on offline login based application using SQLite. For the purpose of security i need to move to login activity if the app has minimized. i tried this code in onPause function
#Override
protected void onPause() {
Intent intent = new Intent(dashboard.this, login.class);
startActivity(intent);
finish();
super.onPause();
}
when i try to move from that activity to another also it moves to the login activity. i hope when im moving to another activity current activity is set to paused. that's why it moves to login activity.
you must set a Boolean to handle loginActivity ;
boolean mustGoToLoginActivity=true;
when you want to go to another Activity first set this boolean to false for example :
public void goToAnotherActivity(){
mustGoToLoginActivity=false;
//...
startActivity(anotherActivity);
}
and in onResume() methode set taht to true .
then in onPause() method :
#Override
protected void onPause() {
if(mustGoToLoginActivity){
Intent intent = new Intent(dashboard.this, login.class);
startActivity(intent);
finish();
}
super.onPause();
}
You are right, this scenario will not work. What you can do is use a static boolean to achieve the behavior like this.
public class MainActivity extends AppCompatActivity {
static Boolean navigateToLogin =false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (navigateToLogin) {
move();
navigateToLogin =false;
}
}
private void move() {
Intent intent = new Intent(this, newActivity.class);
startActivity(intent);
}
#Override
protected void onPause() {
super.onPause();
navigateToLogin = true;
}
}
I have an Activity A that uses an intent to go to Activity B. Sometimes Activity A start also another activity, Activity C.
Is there a way for Activity A to know from which Activity (B or C) it is restarted when these activities finish?
You could use method startActivityForResult instead of startActivity to start your activity B or C. If B or C than returns a result that identifies itself you can read it.
From your Activity A, call following methods, suppose you have two buttons and on click of them start Activity B or Activity C:
public void StartOtherActivityB() {
Intent aIntent = new Intent(LauncherActivity.this, OtherActivityB.class);
startActivityForResult(aIntent, REQUEST_ACTIVITY_B);
}
public void StartOtherActivityC() {
Intent aIntent = new Intent(LauncherActivity.this, OtherActivityC.class);
startActivityForResult(aIntent, REQUEST_ACTIVITY_C);
}
and implement onActivityResult() method as follows
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_ACTIVITY_B){
//class restarted from ACTIVITY_B
}else if (requestCode ==REQUEST_ACTIVITY_C){
//class restarted from ACTIVITY_C
}
}
Use a static variable to store the last activity started, so when activity A is resumed, you can check it.
private boolean isB = false;
public void startActivity(Class<?> activityName){
Intent intent = new Intent(this, activityName);
isB = activityName.getName().equals(B.class.getName());
startActivity(intent);
}
like Juanjo Vega said,
use the activitylifecycle methods to do this.....
take a look at the methods....
LifecycleMethods-android
you can set up a global variable or something (as per your logic) in the onResume() method of the activity which you want to get notified. onResume() will cal after onPause which trigger your logic...
for setting up globals you can use singleTons or the Application class
check out your self , you will come to know easily
public class MainActivity extends Activity {
Button clikBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("onCreate", "111111111");
Toast.makeText(MainActivity.this,"onCreate...",Toast.LENGTH_LONG).show();
setContentView(R.layout.activity_main);
clikBtn = (Button)findViewById(R.id.clickBtn);
/*clikBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
}
});*/
}
public void clickButton(View v){
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
}
#Override
protected void onStart() {
super.onStart();
Toast.makeText(MainActivity.this,"onStart...",Toast.LENGTH_LONG).show();
Log.e("onStart","999999999");
}
#Override
protected void onPause() {
super.onPause();
Toast.makeText(MainActivity.this,"onPause...",Toast.LENGTH_LONG).show();
Log.e("onPause", "222222222");
// notify("onPause");
}
#Override
protected void onResume() {
super.onResume();
Toast.makeText(MainActivity.this,"onResume...",Toast.LENGTH_LONG).show();
Log.e("onResume", "333333333");
//notify("onResume");
}
#Override
protected void onStop() {
super.onStop();
Toast.makeText(MainActivity.this,"onStop...",Toast.LENGTH_LONG).show();
Log.e("onStop", "444444444");
//notify("onStop");
}
#Override
protected void onDestroy() {
super.onDestroy();
Toast.makeText(MainActivity.this,"onDestroy...",Toast.LENGTH_LONG).show();
Log.e("onDestroy", "55555555");
//notify("onDestroy");
}
#Override
protected void onRestart() {
super.onRestart();
Toast.makeText(MainActivity.this,"onRestart...",Toast.LENGTH_LONG).show();
Log.e("onRestart","66666666");
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Toast.makeText(MainActivity.this,"onRestoreInstanceState...",Toast.LENGTH_LONG).show();
Log.e("onRestoreInstanceState", "777777777");
//notify("onRestoreInstanceState");
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Toast.makeText(MainActivity.this,"onSaveInstanceState...",Toast.LENGTH_LONG).show();
Log.e("onSaveInstanceState", "8888888888");
//notify("onSaveInstanceState");
}
}
I have a couple of activities that extends from a custom class I wrote which in turn extends from Activity. I've named this class LoginFinisherActivity and on overriden its onCreate function like this
private BroadcastReceiver finishReceiver = null;
public static final String ACTION_FINISH_LOGIN = "ACTION_FINISH_LOGIN";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("LoginFinisherActivity", "onCreate() called.");
finishReceiver = new FinishReceiver();
registerReceiver(finishReceiver, new IntentFilter(ACTION_FINISH_LOGIN));
}
Now the activities that extended LoginFinisherActivity are the ones that need to retain their states whenever I click the system's back button. i.e. I'm at a welcome activity and I want to go to and forth to a sign up/sign in activities. But when I either sign in or sign up, I land on NavigationActivity which extends Activity, i.e. it needs to be closed down not gone back to whichever activity it came from.
I was able to do that if I removed the onPause and onResume functions from the LoginFinisherActivity.
My FinishReceiver's code is as follows:
private final class FinishReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_FINISH_LOGIN)) {
finish();
}
}
}
Thank you for your help in advance.
Edit: following are the overriden onPause and onResume functions in the LoginFinisherActivity
#Override
protected void onPause() {
Log.d("LoginFinisherActivity", "onPaused() called.");
super.onPause();
if(finishReceiver != null) {
unregisterReceiver(finishReceiver);
finishReceiver = null;
}
}
#Override
protected void onResume(Context context, Intent intent) {
Log.d("LoginFinisherActivity", "onResume() called.");
super.onResume();
if (intent.getAction().equals(ACTION_FINISH_LOGIN)) {
finish();
}
else {
if(finishReceiver == null)
registerReceiver(finishReceiver, new IntentFilter(ACTION_FINISH_LOGIN));
}
}
Assuming you want to finish your activities on successful login/register, I think the best approach would be using startActivityForResult(Intent intent, int REQUEST_CODE) instead of handling more intents that make the flow more complex.
You can also make use of android.support.v4.content.IntentCompatIntentCompat.makeRestartActivityTask(...) if you want to terminate the previous stack of activities.
Hope it helps.
In my app, whenever I receive a push notification, I will perform a check if my mainActivity is visible to the user to do something...
I have a static boolean value that is set true inside onResume of mainActivity, and false inside it's onPause.
What should I do inside the onMessage
#Override
protected void onMessage(Context context, Intent intent)
{
if(mainActivity == visible)
//do something inside mainactivity.. change text inside edittext
else
//do something else
}
any insights ?
I'm not a fan of keeping static references to activities. I think they're a can of worms ready to explode on you. So you'll suggest an alternative to #TeRRo answer:
on your global BroadcastReceiver onMessage you'll send a LocalBroadcast that your activity will be listening to. Like this:
private static final String ACTION_PUSH_RECEIVED = "com.myapp.mypackage.action.pushReceived";
public static final IntentFilter BROADCAST_INTENT_FILTER = new IntentFilter(ACTION_PUSH_RECEIVED);
#Override
protected void onMessage(Context context, Intent intent) {
Intent i = new Intent(ACTION_PUSH_RECEIVED);
i.putExtra( ... add any extra data you want... )
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
}
and now we make the activity listen to it:
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(context)
.registerReceiver(mBroadcastReceiver, BroadcastReceiverClass.BROADCAST_INTENT_FILTER);
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(context)
.unregisterReceiver(mBroadcastReceiver);
super.onPause();
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
// read any data you might need from intent and do your action here
}
}
To avoid this, you should manage activities references. Add the name of the application in the manifest file:
<application
android:name=".MyApp"
....
</application>
Your application class :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Create a new Activity :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (currActivity != null && currActivity.equals(this))
mMyApp.setCurrentActivity(null);
}
}
So, now instead of extending Activity class for your activities, just extend MyBaseActivity. Now, you can get your current activity from application or Activity context like that :
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
Or why don't you use the Local broadcasts when you receive the push notification, and receive it in your activity, and do respective changes or actions.
And if they are UI intensive tasks, bind your activity to a service, and receive the push notification and perform the action in this service and use the result in the activity.
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();
}
});