how to know if an activity has started already - android

I'm working in a app ,where I filter if screen is on or off and launch an activity when the screen is on, but sometime it launch the activity but the activity was started already , i would like to ask you if it was any way to know inside my app if an activity is already launched.
When i start the activity i added this code
intent11.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Thank you so much.

I think that you can set variable with activity life cycle
class IAMActivity extends Activity {
static boolean isStart = false;
public void onStart() {
super.onStart();
isStart = true;
}
public void onStop() {
super.onStop();
isStart = false;
}
}

Here is what you are looking for:
class MyActivity extends Activity {
static boolean alreadyLaunched = false;
#Override
public void onStart() {
super.onStart();
alreadyLaunched = true;
}
#Override
public void onStop() {
super.onStop();
alreadyLaunched = false;
}
}

If you want to restrict your activity to one instance, you can set the launchMode in the manifest file to either singleTask or singleInstance, depending on your requirements.
<activity
android:launchMode="singleTask"
...>
...
</activity>
With singleTask a new intent is delivered via onNewIntent() instead of onCreate().
See <activity> for more details.

Related

What's the proper way to initialize an Android application?

Problem: I need to run some code at every start before my app is ready to be used.
At first, I tried doing it in a dedicated activity.
AndroidManifest.xml
<activity android:name=".MainActivity" />
<activity android:name=".StarterActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
AppLoader.java
public class AppLoader {
private static Object someInstance;
public static void load(Runnable onCompleteCallback) {
try {
someInstance = new Object();
//potentially long operation to initialize the app
Thread.sleep(5000);
onCompleteCallback.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void checkInitialized() {
if (someInstance == null) {
throw new RuntimeException("Not initialized");
}
}
}
StarterActivity.java
public class StarterActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppLoader.load(() -> {
MainActivity.start(this);
finish();
});
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static void start(Context context) {
Intent starter = new Intent(context, MainActivity.class);
context.startActivity(starter);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppLoader.checkInitialized();
}
}
This works fine if the app is cold started via the launcher icon but crashes in all other cases. Simple way to reproduce the issue:
Go to developer settings on your device and set "Background process limit" to "No background process"
Open the app
Open some other app
Open the app again. Result: it crashes.
Here's an article describing a similar problem: Android process death — and the (big) implications for your app
Possible solutions:
Lazy loading/reactive approach. I try to use it as much as possible but there is always some code I need to run in a blocking way before user can interact with the app so this is not enough.
Putting all of that code in App.onCreate(). This would probably work for small apps but I've seen large apps that take 5-10 seconds to initialize, and I doubt they use onCreate() for that. Possible downsides: ANR and/or excessive startup time in Android Vitals?
Checking if the app is initialized in a BaseActivity, but that would require either blocking onCreate or managing lifecycle callbacks manually which doesn't sound like a good idea.
So, what's the proper way to run some code every time the app is launched?
Note: Normally StarterActivity would be a splash screen, AppLoader would be injected, etc, but I left that out for simplicity.
AndroidManifest.xml
<application
android:name=".AppLoader"
AppLoader.java
public class AppLoader extends Application {
private static Object someInstance;
#Override
public void onCreate() {
super.onCreate();
// DO YOUR STUFF
}
}
Update
- Use Handler with splash screen.
public class StarterActivity extends AppCompatActivity {
private Handler handler;
private Runnable myStuffRunnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
myStuffRunnable = new Runnable(){
public void run(){
// DO MY STUFF
MainActivity.start(this);
}
};
}
#Override
protected void onPause() {
handler.removeCallbacks(myStuffRunnable);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
handler.post(myStuffRunnable);
}
#Override
protected void onDestroy() {
handler.removeCallbacks(myStuffRunnable);
super.onDestroy();
}
}
Your app is throwing the RuntimeException you set in AppLoader.checkInitialized() method, because your someInstance object is losing it's state when the app goes to background and gets killed by the system ('cause you have set your device to hold zero background threads). So, when you try to reopen the app, the system launches MainActivity directly (and not StarterActivity) because it is trying to restore it's previous state. But variables are not restored, not even static variables.
So, if you need the Object someInstance on your MainActivity, you should integrate it's instantiation into MainActivitie's lifecycle, overriding methods like onSavedInstanceState, onRestoreInstanceState, etc, to properly handle and reaload this object if your app gets killed by the system.
Take a look on this https://developer.android.com/guide/components/activities/activity-lifecycle
If anyone's interested, I ended up just redirecting the user to StarterActivity if needed to make sure the necessary code is executed at every start.
public abstract class BaseActivity extends AppCompatActivity {
private boolean isCreated;
#Override
protected final void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!appLoader.isLoaded()) {
StarterActivity.start(this);
finish();
return;
}
onCreateActivity(savedInstanceState);
isCreated = true;
}
protected void onCreateActivity(#Nullable Bundle savedInstanceState) {
}
#Override
protected final void onDestroy() {
super.onDestroy();
if (isCreated) {
onDestroyActivity();
}
}
protected void onDestroyActivity() {
}
}
All activities extend BaseActivity (except StarterActivity) and override onCreateActivity/onDestroyActivity instead of onCreate/onDestroy.

Check if activity onStop is called while starting a new activity

I am trying to solve a problem. In my application I need to determine if onStop method was called because of starting a new activity or it was called after user had clicked on the home button or had switched to another app.
I have BaseActivity class, and I need to check it here.
I have tried to find a way to do this, but unfortunately still no solution is found.
Maybe there is a workaround for that.
The idea is to differentiate the initiator of onStop method call.
I would be grateful for any help.
A possible solution would be to register an ActivityLifecycleCallbacks and save the reference name of the last activity that called onResume:
public class ActivityChecker implements Application.ActivityLifecycleCallbacks {
private static ActivityChecker mChecker;
private String mCurrentResumedActivity = "";
public static ActivityChecker getInstance() {
return mChecker = mChecker == null ? new ActivityChecker() : mChecker;
}
// If you press the home button or navigate to another app, the onStop callback will be called without touching the mCurrentResumedActivity property.
// When a new activity is open, its onResume method will be called before the onStop from the current activity.
#Override
public void onActivityResumed(Activity activity) {
// I prefer to save the toString() instead of the activity to avoid complications with memory leaks.
mCurrentResumedActivity = activity.toString();
}
public boolean isTheLastResumedActivity(#NonNull Activity activity) {
return activity.toString().equals(mCurrentResumedActivity);
}
// [...] All other lifecycle callbacks were left empty
}
The ActivityLifecycleCallbacks can be registered in your Application class:
public class App extends Application {
public App() {
registerActivityLifecycleCallbacks(ActivityChecker.getInstance());
}
}
Don't forget to register it in your manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="your.package.name">
<application
...
android:name=".App"
> ...
</application>
</manifest>
Then, you can use it in your base Activity.
public class MyBaseActivity {
#Override protected void onStop() {
if(ActivityChecker.getInstance().isTheLastResumedActivity(this)) {
// Home button touched or other application is being open.
}
}
}
References:
Registering your custom Application class and the ActivityLifecycleCallbacks: https://developer.android.com/reference/android/app/Application.html
After writing this I found this link with some other options to retrieve the current resumed activity: How to get current foreground activity context in android?.
You can use SharedPreferences to check it:
#Override
protected void onStop() {
super.onStop();
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
pref.edit().putBoolean("IfOnStopCalled", true).apply();
}
Check in your BaseActivity:
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
Boolean IfOnStopCalled = pref.getBoolean("IfOnStopCalled",false);
if(IfOnStopCalled){
//Do your action
}
else{
//Do your action
}

Clear the Activity History Stack once inside Main activity

I want to clear the HistoryStack once I have started my MainAcitivty that is inside its oncreate() method of Main.
Due to some issues I cant use android:noHistory="true" because it creates problem for my gPlus signing in, also cant use finish() FLAG_ACTIVITY_NO_HISTORY for similar reasons.
I only want it to be removes in particular case that is when inside Main, otherwise it should be there on History stack.
Once in Main all history stack should be clear and over pressing back the app should exit. Is it possible, if yes how, please explain.
For no recents activities use android:excludeFromRecents="true" in desire activity.
You could add a BroadcastReceiver in all activities you want to finish.
public class MyActivity extends Activity {
private FinishReceiver finishReceiver;
private static final String ACTION_FINISH =
"com.mypackage.MyActivity.ACTION_FINISH";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finishReceiver = new FinishReceiver();
registerReceiver(finishReceiver, new IntentFilter(ACTION_FINISH));
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(finishReceiver);
}
private final class FinishReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_FINISH))
finish();
}
}
}
You can close those Activitys by calling
sendBroadcast(new Intent(ACTION_FINISH));
Check this example for details:
http://www.hrupin.com/2011/10/how-to-finish-all-activities-in-your-android-application-through-simple-call

Calling finish() in onStop()

What happens when finish() method is called in onStop() method?
Does it causes anr : means it calls
onPause()->onStop()->finish()->onPause()....
or it finishes the activity : means it calls directly
onDestroy()
Actually, I want to finish my activity when it is completely invisible.
EDIT:
See this scenario, I launch an activity B whose layout height and
width is smaller than activity A, so activity A is partially visible
and when I press the home button activity A becomes completely
invisible. At this point I want to close activity A, so that it do not
call onRestart().
Thanks in advance.
It finishes the activity and onDestroy() is called. If you want to finish your activity when it is invisible then you should call finish() in onStop().
according to your scenario, maintain one flag in MainActivity indicating that other Activity is launched or not? and make sure yourself to finish MainActivity or not based on that flag ...
this may help you...
public class MyActivity extends Activity {
private boolean isSecondActivityLaunched;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
isSecondActivityLaunched = false;
}
public void onClick(View view) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
isSecondActivityLaunched = true;
}
#Override
protected void onStop() {
super.onStop();
if(!isSecondActivityLaunched) {
finish();
}
}
}
It will be best way in your case to call finish() ;
Thanks

Broadcast-receiver must not start new Activity if my Application is Shown?

I have BroadcastReceiver when new Message is received will start MessageActivity, but how not to start this Activity if my MainActivity is in front of screen?
By the way, I am trying to not use Singleton Activity.
You will need to keep track of your Activity with OnResume and onPause methods.
So something like this should help you to check if MainActivity is on foreground.
private boolean isForeground;
public void onResume() {
isForeground = true;
}
public void onPause() {
isForeground = false;
}

Categories

Resources