How to differentiate activity launch from launcher or up navigation - android

I need a method to differentiate between activity launches from the launcher or another activity's up navigation. I have a setting preference to show a tutorial the next time the app is started, but the tutorial is called when I press up on the settings activity.
I've tried the methods described here (using intent.getAction() and intent.getCategories()) Differentiating between an Activity launch from home screen or from another activity from App but they don't work when I use up navigation instead of the back button

Just define global static boolean and set it true eg. isLaunch=true on your main activity and apply condition to check if isLaunch = true before calling method that displays tutorial and set it to false if it is true
public class MainActivity{
private static boolean isLaunch = true;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(isLaunch){
isLaunch = false;
YourTutorialDisplayingMethod();
}
}
}

check the activity lifecycle method.OnCreate() is called only once when your activity is launched.But if you start a new activity from this activity without finishing it,then coming back from the newly opened activity using up navigation wont call the onCreate of your acticity

Related

Override onSavedInstanceState: savedInstanceState object is always null

I have two activities (A and B). Activity A calls activity B. Activity B has Back (Up) button like this:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Now when this UP button is pressed, onCreate of activity A is again called. In the activity A, there is a classId variable (which I got from an Intent) which I want to retain. For this I have following code in my onCreate of activity A:
if (savedInstanceState == null)
{
Intent intent = getIntent();
classId = intent.getIntExtra("CLASS_ID", 0);
}
else
{
classId = savedInstanceState.getInt("CLASS_ID");
}
I have also overriden the onSavedInstanceState method:
#Override
protected void onSaveInstanceState(Bundle savedInstanceState)
{
savedInstanceState.putInt("CLASS_ID", classId);
super.onSaveInstanceState(savedInstanceState);
}
I am following this SO answer:
onCreate being called on Activity A in up navigation
The problem I am facing is that when I come again to activity A by passing back button in activity B, onCreate gets called and I found savedInstanceState to be NULL.
Edit:
Is there any other way to save my classId variable so that when I return again to activity A, I can use that?
Edit 2
If I set launch mode of my activity A to SingleTop in the manifest file, my issue gets resolved. Is it the right approach?
You should not suppose that onSaveInstanceState called each time you go to next activity.See the docs
This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state. For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(Bundle) or onRestoreInstanceState(Bundle).
You may further consult with official docs here
Try this
public class SingletonHolder {
//your id here as what data type you want
private static SingletonHolder instance;
public static SingletonHolder getInstance() {
if (instance == null) {
instance = new SingletonHolder();
}
return instance;
}
//set getter setter here
}
If not successfull feel free to comment
I changed the launchMode of the activity A to singleTop in the mainfest file like this:
android:launchMode="singleTop"
I followed this question on SO: Setting launchMode="singleTask" vs setting activity launchMode="singleTop"
By using this approach, activity A is not destroyed and when I just finish the activity B or click UP navigation in activity B, the existing instance of activity A is launched again.

Checking condition before starting an activity

I want to check some condtiton before the main activity starts and based on test result i have to either start a new activity or continue the same activity. How to do this?
you can check it in your OnCreate() method. It is called when your activity start.
onCreate(...){
....
if(want this){
//continue;
}else{
// start new activity
}
}
The default Activity to start is set in the manifest, so a better approach to your problem would be to use fragments. Keep in mind that fragments are faster/lighter, so instead of using Application as a "decision" class to start activities (bad practice), use your main activity. In your onCreate() method, check for your condition and attach the needed fragment.
I am using java annotation to handle this case:
Create the Annoation class
Create CustomContext.java with a startActivity method in it
Create the Interceptor.java
Create a class which implement Interceptor like this (named DemoInterceptor.java here)
Declare a static variable of DemoInterceptor in your activity. and the demo Activity should like this then, start the activity via the custom startActivity in step #2
enjoy and let me know if you have any further question.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(startNewActivity) {
// TODO Fire off intent to start new activity
finish(); // Closes the current activity
return;
}
// TODO Code for current activity.
}
startNewActivity is a boolean indicating whether to launch a new activity or not. It should be assigned a value depending on your condition.

Starting a new activity from ViewPager and going back to the same page

In my app there is a viewpager with 3 fragments in it.
In one of the fragments I'm starting another activity.
I want the user to go back to the same viewpager page he were in before on back/up.
I implemented it successfully using the activity that hosts the viewpager's onPause and onResume methods. It worked but the problem was that onResume was being fired after onCreate, which resulted in the app starting at the same page (instead of a "default", different page I set in the onCreate method).
I then tried to place the onResume code in the launching activity's onOptionsItemSelected method, but that didn't work at all.
Launched activity:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
vpPref = getPreferences(MODE_PRIVATE);
int value = vpPref.getInt("viewPagerPage", -1);
if (value != -1) {
MainActivity.instance.mPager.setCurrentItem(value);
vpPrefEditor = vpPref.edit();
vpPrefEditor.remove("viewPagerPage");
vpPrefEditor.commit();
}
return true;
}
return super.onOptionsItemSelected(item);
}
Main Activity: (hosts the viewpager)
public void onPause() {
super.onPause();
vpPref = getPreferences(MODE_PRIVATE);
vpPrefEditor = vpPref.edit();
vpPrefEditor.putInt("viewPagerPage", mPager.getCurrentItem());
vpPrefEditor.commit();
}
The problem is in the first code. I don't know whether this is a placement problem or getting the wrong instance of MainActivity that is wrong...
What could be the cause to this behavior?
That's a bad way of accessing the ViewPager from MainActivity(I hope MainActivity.instance isn't a static field holding a reference to a MainActivity instance). You should let the MainActivity completely handle the ViewPager's position:
In the onPause() of the MainActivity you would keep the current code. In the onResume() method of the MainActivity you would have:
#Override
public void onResume() {
super.onResume();
vpPref = getPreferences(MODE_PRIVATE);
final int value = vpPref.getInt("viewPagerPage");
final boolean shouldRestore = vp.getboolean("restoreStatusFlag");
// we are again in the MainActivity so also make
// restoreStatusFlag as false in the preferences
if (shouldRestore) {
mPager.setCurrentItem(value);
}
}
The shouldRestore preference would be set from the launched activity in the onCreate. This way if MainActivity is started you'll keep the default page(shouldRestore will be false as the launched activity didn't run yet). If after MainActivity you go to the launched activity shouldRestore will become true(you need to set it in the onCreate) and as you come back the ViewPager will be set to the right page in onResume().
This leaves one scenario where the user could go to the launched activity(the shouldRestore will be true) but never comes back to MainActivity with BACK. For this you could test the category from the Intent that started MainActivity(which I'm assuming is the one mentioned in the manifest as the launcher activity):
Set<String> catg = getIntent().getCategories();
for (String cat : catg) {
if (cat.equals(Intent.CATEGORY_LAUNCHER)) {
// reset the shouldRestore flag to false so we end up with the default page
break;
}
}

About launcher intent

I'm trying to make a certain function to start only when a user,
Opens the app for the first time,
Goes back to an app from home.
But not start if the user switches between activities within the app.
I have looked through this topic,and the best answer is to use singleTask with onNewIntent(). So, if a user is goes back to the app from Home, a onNewIntent call with the launcher intent passed to it can be used.
However, here is my code:
public class AdMobSDK_DFP_Interstitial extends Activity implements AdListener {
private static final String MOBMAX_INTERSTITIAL_AD_UNIT_ID = "/7732/test_portal7/android_app1_test_portal7/splash_banner_android_app1_test_portal7";
private DfpInterstitialAd interstitialAd;
private int num = 0;
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
Log.d("flow", "onNewIntent");
}
If I switch between different activities in the app, onNewIntent() is always called, which is the same as I go back to the app from Home.
First thing you can do is to implement your own "Application" object and have it run the needed function when it is created.
public class MyApplication extends Application {
#Override
public void onCreate() {
// Call your function
}
}
Your application object will be live as long as your app is alive (any activity/service is still running), but note that the Application object is not destroyed immediately when the user presses "Home", and might stay alive for a while and a user can return to it without the function being called.
If you need this function to run as part of your main activity, just save a flag in your Application context :
public boolean alreadyDisplayed = false; and then in your activity's onStart you can just call
if ((MyApplication)getApplication().alreadyDisplayed ) {
// Call your function
(MyApplication)getApplication().alreadyDisplayed = true;
}
** If this solution is not enough for you and you need to call your function every time your main activity is displayed from the home page you'll need to do something not as nice... one suggestion I can give you is to implement the same Application object but this time with an "open activity" counter:
public class MyApplication extends Application {
public int mActivityCounter = 0;
}
Then you can increment this counter on every onStart of activity in your app and decrement on every onStop (of course this can be done by implementing a class MyActivity and make all your relevant activities inherit it. Then you can use this counter to know if there are any other activities opened. Note that you'll have to make sure the access to this counter is synchronized and work your way with it as you need.
I hope this helps...

onBackPressed() behaviour with ActivityGroups

Quick question: I have an activitygroup. Within that Activitygroup I have an activity. If I press back while inside this activity. the onBackPressed method of the activity is called - Not the Activitygroups onBackPressed - Why is that ?
EDIT: Got my answer but the problem remains. Here follows code and explanation of my original issue:
I am using ActivityGroups within a TabHost and as such have been "forced" into overriding onBackPressed. I can navigate through my application without issue by pressing back on my phone and by pressing the tabs on my tabhost. But I cannot interact with the interface after pressing Back.
Once I press one of the tabs on the tabhost again I can interact with everything like normal. Why is this happening? Do I need to override onResume?
Relevant code
SettingsActivityGroup :
public class SettingsActivityGroup extends ActivityGroup
{
// Keep this in a static variable to make it accessible for all the nested activities, lets them manipulate the view
public static SettingsActivityGroup group;
// Need to keep track of the history if you want the back-button to work properly, don't use this if your activities requires a lot of memory.
private ArrayList<View> history;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Allocate history
this.history = new ArrayList<View>();
// Set group
group = this;
// Start root (first) activity
Intent myIntent = new Intent(this, SettingsActivity.class); // Change to the first activity of your ActivityGroup
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
ReplaceView("SettingsActivity", myIntent);
}
/*
* Replace the activity with a new activity and add previous one to history
*/
public void ReplaceView(String pId, Intent pIntent)
{
Window window = getLocalActivityManager().startActivity(pId, pIntent);
View view = (window != null) ? window.getDecorView() : null;
// Add the old activity to the history
history.add(view);
// Set content view to new activity
setContentView(view);
}
/*
* Go back from previous activity or close application if there is no previous activity
*/
public void back()
{
if(history.size() > 1)
{
// Remove previous activity from history
history.remove(history.size()-1);
// Go to activity
View view = history.get(history.size() - 1);
Activity activity = (Activity) view.getContext();
// "Hack" used to determine when going back from a previous activity
// This is not necessary, if you don't need to redraw an activity when going back
activity.onWindowFocusChanged(true);
// Set content view to new activity
setContentView(view);
}
else
{
// Close the application
finish();
}
}
/*
* Overwrite the back button
*/
#Override
public void onBackPressed()
{
// Go one back, if the history is not empty
// If history is empty, close the application
SettingsActivityGroup.group.back();
return;
}
}
Arbitrary child of SettingsActivityGroup(CallForwardActivity)
public class CallForwardActivity extends ListActivity
{
....
#Override
public void onBackPressed()
{
// Go one back, if the history is not empty
// If history is empty, close the application
SettingsActivityGroup.group.back();
return;
}
}
Because I believe calling onBackPressed() of the currently selected activity is the desired behavior.
It's also worth noting that ActivityGroup is deprecated, but I assume you are coding for <3.0 and don't fancy working with the support libraries.
Regarding your edited question:
Another question on this site cites this article as a good ActivityGroup example, and I would agree http://ericharlow.blogspot.com/2010/09/experience-multiple-android-activities.html
This example just calls finish() on the current activity when back is pressed, and lets the os restart the previous activity, which is simpler than what you are doing, and will hopefully work! You can just call getParent() in your child activities too to avoid using that static reference (just seems easier to read to me that way!).

Categories

Resources