Hey I have an application where I want to now when the APP goes to onPause or onDestroy because I want to call a certain function when this happens.
I tried to override the onPause in an activity and extended that activity in all project but the onPause was being called on every migration between activities (which is logical) but this is not what I want.
I want to know when the user exits the app or pauses it (pressing the home button)
Regards,
Pull this dependency in your build.gradle file:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
Then in your Application class, use this:
public class MyApplication extends Application implements LifecycleObserver {
#Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackgrounded() {
Log.d("MyApp", "App in background");
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForegrounded() {
Log.d("MyApp", "App in foreground");
}
}
Update your AndroidManifest.xml file:
<application
android:name=".MyApplication"
....>
</application>
in all of your activities :
#Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
Log.e("TAG", "Activity Minimized");
}
in your main activity :
#Override
public void onBackPressed() {
Log.e("TAG", "App Exit");
super.onBackPressed();
}
note : there is no way to detect when app killed by system ( for example quit with task manager )
I use this method to detect if the app goes to background or is killed
step 1:
Make a service like this
public class OnClearFromRecentService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("ClearFromRecentService", "Service Started");
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("ClearFromRecentService", "Service Destroyed");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.e("ClearFromRecentService", "END");
//Code here
stopSelf();
}
}
step 2)register this service in manifest.xml
<service android:name="com.example.OnClearFromRecentService" android:stopWithTask="false" />
step 3) Then start this service on your splash activity
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
So now when your app is manually killed, the onDestroy method will be called
Try this on your code and let me know if its working.
Happy Coding :)
If the user exits the application the onDestroy() callback will be called, if the user presses the home button the onStop() callback will be called.
So you want to know when the whole Application goes into Bacground, the method from Activity.onPause tells you when a single abtivity goes into background.
For your needs you could add
to your android manifest. this will call a class like this with name "YourApplication"
public class YourApplication extends Application {
#Override
public void onCreate() {}
public public void onTerminate() {
super.onTerminate();
}
}
e.g. for "onCreate" or "onTerminate" of the whole App (not for every single Activity).
But java documentation say you should not trust that onTerminate is called on every app destroy (see: android.app.Application subclass, onTerminate is not being called).
I Think the best way is, if you
add a own Methode "onPause" and "onResume" to your Application class
in ALL your Activities you store into Application class when onPause or onResume is called
and you call you own Application.onPause when ALL of you activities are in "onPause"
and you call you Application.onResume when first Activity is back in
"onResume"
Implement
Application.ActivityLifecycleCallbacks
in your Application Class. It will implement the following ActivityLifeCycle Methods :
isActivityVisible()
onActivityCreated()
onActivityStarted()
onActivityResumed()
onActivityPaused()
onActivityStopped()
onActivitySaveInstanceState()
onActivityDestroyed()
And Register the callback listener in OnCreate() of application class like :
registerActivityLifecycleCallbacks(this);
Define a Global variable in application class.
private static boolean isActive;
Now change the activity life cycle's overridden method like this:
public static boolean isActivityVisible() {
return isActive;
}
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
isActive = true;
}
#Override
public void onActivityPaused(Activity activity) {
isActive = false;
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
isActive = false;
}
and you can perform the required operations on the value of isActive variable.
Related
I have a situation, that when my app goes in background (not killed completely!) and last alive activity was BActivity. In this state. I receive a push notification.
When notification is clicked it should open the last activity which was opened earlier i.e., (BActivity).
Question How to open that last specific paused activity?
Is any answer like set flag or manifest configs?
If I understood correctly, you want to bring your app back to foreground after you receive a push notification? In that case, use the following code:
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(intent);
where MainActivity is the launcher Activity that you have specified in AndroidManifest.xml.
This should bring your app to foreground in its previous state, if there ever was one, and otherwise launch MainActivity.
For an explanation see here.
You can try by adding the activity life cycle callback to your application. And judge the activity type of current paused or resumed activity, etc. The sample code:
public static void init(Application app) {
app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
private int activityCount = 0;
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
AppUtils.attachActivity(activity);
}
#Override
public void onActivityStarted(Activity activity) {
activityCount++;
AppUtils.attachForeActivity(activity);
}
#Override
public void onActivityResumed(Activity activity) {
if (!isForeGround) {
isForeGround = true;
notifyForegroundChange(true);
}
}
#Override
public void onActivityPaused(Activity activity) {
// no-op
}
#Override
public void onActivityStopped(Activity activity) {
AppUtils.detachForeActivity(activity);
activityCount--;
if (activityCount == 0) {
isForeGround = false;
notifyForegroundChange(false);
Log.i(TAG, "Activity foreground: " + System.currentTimeMillis());
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
// no-op
}
#Override
public void onActivityDestroyed(Activity activity) {
AppUtils.detachActivity(activity);
}
});
}
Here we use the activityCount filed to calculate current actived activities count. When it's 0, the app is background, otherwise foreground. You can judge the activity type by the callback method provided.
Hope it helps!
I have created a service and called this service class from BaseActivity.
Intent serviceIntent = new Intent(this, UserAvailabilityService.class);
startService(serviceIntent);
public class UserAvailabilityService extends Service {
private static final String TAG = UserAvailabilityService.class.getSimpleName();
boolean isChecked = false;
boolean isUserAvailable = false;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate()");
isChecked = getAvailableStatusFromFref();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand()");
return START_NOT_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.i(TAG, "onTaskRemoved()");
if(isChecked) {
//Hit a api
}
else
{
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy()");
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.i(TAG, "onLowMemory()");
}
}
If app crashes or closed from task manager then that time i want to hit api.
Right Now, When i am swipping the app from background this onTaskRemoved method is calling. and i am hitting the api.
But when i am closing the same app from task manager (Setting->Apps->App name->Force Stop) then this onTaskRemoved method is not calling.
Any idea,please let me know.
Not possible. You cannot tell from within an app whether the app will be terminated. You could watch for termination from a second app, but at any time the first can be closed without notice. Not to mention the variety of ways that both apps could be shut down (for example, they could just pull the battery). You should never write code that requires you to do something on shutdown, because it will never be reliable.
The best you can do is calling isFinishing() which checks if it is being destroyed from you onPause() method
#Override
protected void onPause(){
super.onPause();
if(isFinishing){
callApi();
}
}
How could I know if an activity is the top of stack? I thought about using onResume/onPause, but this is not exactly, as it would fail once the app goes to background.
The fact is that I'm sending a broadcast receiver that is received for all activities (I have a BaseActivity that is extended by all activities and that registers to the broadcast). So, only the activity that is at the top of the stack must react to the broadcast. If I use the isResumed() then it would work always but when the app goes to background. Any idea?
Thanks in advance!
in base activity you register the broadcast Receiver and in receiver function you call one abstract function which one is implemented by all child activities.
The activity which is on top will automatically receive that function call.
Edit sample code:
public abstract class BaseActivity extends AppCompatActivity {
private static final String NOTIFICATION_ARRIVED = "arrived";
public abstract void receivedFunction(Intent intent);
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
displayToast(" received in Base");
receivedFunction(intent);
}
};
public void displayToast(String s) {
Toast.makeText(this,s,Toast.LENGTH_SHORT).show();
}
#Override
public void onResume() {
super.onResume();
registerReceiver(mMessageReceiver, new IntentFilter(BaseActivity.NOTIFICATION_ARRIVED));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(mMessageReceiver);
}
}
public class MainActivity extends BaseActivity {
#Override
public void receivedFunction(Intent intent) {
displayToast(" received in child");
}
// do whetever you want . if you ovveride onpause and onResume then call super as well
}
or any other child
public class MainActivity2 extends BaseActivity {
#Override
public void receivedFunction(Intent intent) {
displayToast(" received in child");
}
// do whetever you want . if you ovveride onpause and onResume then call super as well
}
// to broadcast
Intent intent = new Intent(BaseActivity.NOTIFICATION_ARRIVED);
sendBroadcast(intent);
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.
I wrote an android program that: has a main activity for UI, and it starts a service. The service timely callbacks the UI activity to update views. It works fine except: if the activity is closed (with BACK) and start again, the service will also be started again (The service plays audio file, so there are two overlapped sounds).
I use bindService with BIND_AUTO_CREATE flag to start and connect to service. According to the document, it should create service only if it doesn't exist, but obviously it starts another instance when opened second time.
All I want is when the activity is closed, the service goes on running, and when the activity opens again, it can reconnect to the service. Is that possible? Or I just misunderstand the usage of service?
Tried more:
Use ICountService (described in .aidl) instead of CountService in bindService Intent. It's onDestroyed is called when the activity is closed.
Below is code of service creating if it helps.
ServiceConnection conn = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName c, IBinder b) {
Log.d("TK","Connected");
//binder = (ICountService.Stub) b;
service = ICountService.Stub.asInterface(b);
try {
service.setCallback(new ICountCallback.Stub(){
#Override
public void alert() {
Log.d("TK","alert!");
}
#Override
public void updateTime(final int sec) {
handler.post(new Runnable(){
#Override
public void run() {
indicator.setText(toText(sec));
}
});
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void onServiceDisconnected(ComponentName c) {
Log.d("TK","Disconnected");
}
};
private void startCountService(){
Intent i = new Intent(ICountService.class.getName());
boolean ok = context.bindService(i, conn, Context.BIND_AUTO_CREATE);
Log.d("TK", "bindService="+ok);
}
According to the document, it should create service only if it doesn't exist, but obviously it starts another instance when opened second time.
bindService() will create the service instance if the service is not running. unbindService() will destroy the service instance if there are no other bound connections and nobody called startService(). If the service is destroyed on unbindService(), then a subsequent bindService() will create a new service instance.
IMHO, ideally, unbindService() would not immediately destroy the service, but let it linger for a few seconds first, in case there is a bindService() shortly after the unbindService(). However, that is not how they implemented it.
All I want is when the activity is closed, the service goes on running, and when the activity opens again, it can reconnect to the service.
You should be using startService() and stopService() instead of (or conceivably in addition to) bindService() and unbindService().
This was worked for me.
Main.java
public class Main extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(Main.this, MyService.class));
try{
MyService.setMainActivity(this);
}catch(Exception e){
//t.setText(e.getMessage());
}
}
}
MyService.java
public class MyService extends Service {
private Context ctx;
public static Main main;
#Override public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onCreate()
{
super.onCreate();
ctx = this;
startService();
}
#Override public void onDestroy() {
// TODO Auto-generated method stub
Log.d("ASAS","Destroy");
super.onDestroy();
}
public static void setMainActivity(Main activity) {
main = activity;
}
private void startService()
{
//timer.scheduleAtFixedRate(new checkdata(),0,30000);
}
}