Android fragment lifecycle issue with actionbar - android

I want to realize the navigation of the fragments using the following code:
public abstract class BaseFragment extends Fragment {
private static String TAG = "BaseFragment";
private BaseFragmentActions baseFragmentActions;
#Override
public void onAttach(Context context) {
super.onAttach(context);
Activity activity = null;
if (context instanceof Activity){
activity = (Activity) context;
}
Log.i(TAG, "onAttach = ");
try {
baseFragmentActions = (BaseFragmentActions)activity;
} catch (ClassCastException e) {
}
Log.i("onAttach",""+(getBackStackCount()!=0));
baseFragmentActions.resetToolbarNavigation(getBackStackCount()!=0);
}
#Override
public void onDetach() {
super.onDetach();
Log.i("BaseFragment", "onDestroy = " + (getBackStackCount() - 1));
baseFragmentActions.resetToolbarNavigation((getBackStackCount() - 1) != 0);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
private int getBackStackCount() {
int b = getActivity().getSupportFragmentManager().getBackStackEntryCount();
Log.i("getBackStackEntryCount", "====== "+b);
return b;
}
public interface BaseFragmentActions {
public void resetToolbarNavigation(boolean backNavigationEnabled);
}
}
All my fragments extend this Base Activity. And inside my main activity i implement BaseFragmentActions, and implemented this method:
#Override
public void resetToolbarNavigation(boolean backNavigationEnabled) {
Log.i("BaseActivity", "reset " + backNavigationEnabled);
getSupportActionBar().setDisplayHomeAsUpEnabled(backNavigationEnabled);
if (backNavigationEnabled) {
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("resetToolbarNavigation", "setNavigationOnClickListener");
onBackPressed();
}
});
} else {
initNavigation();
syncState();
}
}
Everything works fine but when I change the screen orientation we obtain error that getSupportActionBar = null.
This is because of what I call going to attach. How can I fix this error? I tried to make checking whether getSupportActionBar is not zero. I'm not getting an error, but "up" Arrow replaced hamburger...
Advise what you can do in this case. Also share links to navigate the implementation of such fragments. Sorry if something wrong written, or I made a grammatical error)).

Hi sorry for the delay in the answer, the problem you're having is because when onAttach is called the getSupportActionBar() is not set yet, instead you need to make sure the Activity is already created when interacting with Activity components, so just put your call inside the onActivityCreated method of your Fragment like this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
baseFragmentActions.resetToolbarNavigation(getBackStackCount()!=0);
}

Related

How to hide BottomNavigation bar(Botton Navigation Bar Activity) in specific Fragment

I know I am not the first to ask this question but I have referred many SO post regarding this but nothing is solved my query .
What I want to do is in my MainActivity(Bottom Navigation bar Activity) I have Bottom Navigation Bar, In this MainActivity I have cardviews If I clicked on the cardview I need to show another fragment in that fragment I want to hide the bottom navigation bar .And When I nav back to MainActivity botoom Navigation bar should be there.
Here in my case Alarm.java is the fragment where I want to hide the bottom navigation bar.
Alarm.java
public class Alarm extends Fragment {
private OnFragmentInteractionListener mListener;
public Alarm() {
}
public static Alarm newInstance(String param1, String param2) {
Alarm fragment = new Alarm();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_alarm, container, false);
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}
In your MainActivity you can implement two methods that will be responsible for showing and hiding your BottomNavigationView. For example, these two methods animate it sliding up and down:
private void hideBottomNavigationView(BottomNavigationView view) {
view.clearAnimation();
view.animate().translationY(view.getHeight()).setDuration(300);
}
public void showBottomNavigationView(BottomNavigationView view) {
view.clearAnimation();
view.animate().translationY(0).setDuration(300);
}
In MainActivity you call hide right before opening your CardView, and call show in onCreate or onResume.
EDIT:
But, I think that a cleaner way would probably be to create an interface in your Fragment:
public interface OnCardViewOpenedInterface{
void onOpen(); // hide bottom bar when photo is opened
void onClose(); // show bottom bar when photo is opened
}
And call these methods in onStop and onResume of your Fragment:
#Override
public void onStop() {
super.onStop();
mListener.onClose();
}
#Override
public void onResume() {
super.onResume();
mListener.onOpen();
}
And then implement the interface in your MainActivity, override the methods onOpen() and onClose() and inside call your hide and show methods.
They will probably both work, maybe the second one is overcomplicated, it's just I like it more.
I have tried the method by #Suleyman but it didn't work for me. The simplest solution is to use a public static method in the MainActivity and reference it from the fragment where you want to hide the bottom navigation bar.
Don't forget to initialize navView as public static.
In your MainActivity
public static void hideBottomNav(){
navView.setVisibility(View.GONE);
}
public static void showBottomNav(){
navView.setVisibility(View.GONE);
}
In your MyFragment
#Override
public void onResume() {
super.onResume();
MainActivity.hideBottomNav();
}
#Override
public void onStop() {
super.onStop();
MainActivity.showBottomNav();
}

How to show AlertDialog as soon as Fragment created

I'd like to show an AlertDialog (with a couple of Radio Button buttons and an OK button) as soon as a fragment is created.
Where is the best place to call the dialog fragment? I have tried in onViewCreated() and on onResume() and both work, but I am not sure what's best practice.
Also, to ensure the dialog isn't shown every time the fragment is stopped/recreated due, for example, to screen rotation, I have created Boolean value called mShowDialog and set it to 'true' in onCreate() then used an 'If' statement to decide whether the dialog should be shown (see below for example).
onCreate(){
//....
mShowDialog = true;
}
onResume(){
if (mShowDialog){
//....show dialog code
// set mShowDialog to false to ensure code executed only once
mShowDialog = false;
}
}
Is the above code the best way of fulfilling both requirements?
Btw, I am fairly new to programming.
Thanks in advance for the help.
Best practice for this is to inflate dialog in onCreateView() method of fragment.
If you're trying to create it from the activity adding the fragment, I've had good luck with adding a FragmentListener to my fragments and setting it from the activity. This is my basic BaseFragment class that all my fragments extend:
public class BaseFragment extends Fragment {
public Context context;
public Activity activity;
public FragmentListener fragmentListener;
private boolean attached = false;
public BaseFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!isAttached()) {
this.context = activity;
this.activity = activity;
if (this.fragmentListener != null) {
this.fragmentListener.onAttached();
}
setAttached(true);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (!isAttached()) {
this.context = context;
this.activity = (Activity) context;
if (this.fragmentListener != null) {
this.fragmentListener.onAttached();
}
setAttached(true);
}
}
#Override
public void onDetach() {
super.onDetach();
setAttached(false);
if (this.fragmentListener != null){
this.fragmentListener.onDetached();
}
}
public void setFragmentListener(FragmentListener fragmentListener) {
this.fragmentListener = fragmentListener;
}
public View.OnClickListener onBackTapped = new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
};
public boolean isAttached() {
return attached;
}
public void setAttached(boolean attached) {
this.attached = attached;
}
public boolean isPermissionGranted(String permission){
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
public boolean ifShouldShowRationaleForPermission(String permission){
return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
}
public void showPermissionRequest(Activity activity, int requestCode, String... permissions){
ActivityCompat.requestPermissions(activity, permissions, requestCode);
}
}
This way, I can do this in my activity:
MyFragment myFragment = new MyFragment();
myfragment.setFragmentListener(new FragmentListener() {
#Override
public void onAttached() {
// Stuff I want to do when it is attached
}
#Override
public void onDetached() {
// Stuff I want to do when it is detached
}
});
fragmentManager.beginTransaction()
.add(R.id.container, myFragment)
.commit();
And then I can add whatever code I want when the fragment does it's various stuff.
Good luck!

How to have an Activity notify a Fragment that the back button has been pressed

I have been researching this for a few days and have yet to find a working solution. There is lots of information available but because of my inexperience with Android I can't get any of the suggestions to work.
I have an Activity with a stack of 3 Fragments on top of it all of which are presented using FragmentManager Transactions and added to the backstack. While the third Fragment is active, I need to intercept the onBackPressed() method and perform some extra stuff before the Fragment is destroyed.
I have tried using Callbacks and Interfaces to capture onBackPressed() at the Activity and send it to the 3rd Fragment with no luck.
What is the proper way to have a Fragment deep in the stack watch for the Activity's onBackPressed() method.
Let me know if this is not clear.
Thanks for the help.
Not compiled and tested, but this lays out the basic approach:
public interface BackButonListener {
boolean OnBackButtonPressed();
}
public interface BackButtonWatchable {
void addBackButtonListener(BackButtonListener listener);
void removeBackButtonListener(BackButtonListener listener);
}
public class MyActivity extends Activity implements BackButtonWatchable {
...
private static ArrayList<BackButtonListener> backButtonListeners
= new ArrayList<BackButtonListener>();
#Override
public void addBackButtonListener(BackButtonListener listener) {
backButtonListeners.add(listener);
}
#Override
public void removeBackButtonListener(BackButtonListener listener) {
backButtonListeners.remove(listener);
}
...
#Override
public void onBackButtonPressed()
{
boolean supressBackButton = false;
for (BackButtonListener listener: backButtonListeners)
{
if (!listener.OnBackButtonPressed()) {
suppressBackButton = true;
}
}
if (!suppressBackButton) {
super.onBackButtonPressed();
}
}
}
public class MyFragment extends Fragment implements BackButtonListerer {
#Override
public void onResume()
{
((BackButtonWatchable)getActivity()).addBackButtonListener(this);
}
#Override
public void onPause() {
((BackButtonWatchable)getActivity()).removeBackButtonListener(this);
}
}
Crete interface
public interface OnBackPressedListener {
void onBackPressed();
}
and create field in activity
private OnBackPressedListener mListener;
and your onBackPressed() should look like
if (mListener != null) {
mListener.onBackPressed();
} else { /* do your acitivty usual stuff */ }
When fragment is created you register this fragment as mListener in your activity and don't forger to set it to null in onDestroy.
This is the post that answered my question. For a Android newbie, this told me where everything needed to go.
https://stackoverflow.com/a/30865486/2640458
The Fragment that needed to see the onBackPress() method from it's activity:
public class RatingFragment extends Fragment implements ContentActivity.OnBackPressedListener {
#Override
public void doBack() {
getFragmentManager().popBackStack();
}
The very important subscription to the listener in the above Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_rating, container, false);
((ContentActivity)getActivity()).setOnBackPressedListener(this);
}
The Activity that needs to send the onBackPress() method to the above Fragment:
public class ContentActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
#Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
#Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}

How to detect when a fragment appears on the screen?

How could some part of my code be aware of Fragment instance become visible on a screen?
The following snippet will explain my question.
public class MyApp extends Application {
public static final String TAG = MyApp.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
...
#Override
public void onActivityResumed(Activity activity) {
Log.d(TAG, activity.getClass().getSimpleName() + " is on screen");
}
#Override
public void onActivityStopped(Activity activity) {
Log.d(TAG, activity.getClass().getSimpleName() + " is NOT on screen");
}
...
});
}
Here i can track when any activity within my app appears on the screen. Is there any way to extend this approach on Fragments?
Something like
Activity.getFragmentManager().registerFragmentLifecycleCallbacks();
UPD. I know nothing about activities implementations, do they use fragments at all and how do they use them (injection via xml, ViewPager etc.) The only thing I have within my class is an application context. Let's assume Activity and Fragment implementations are black boxes and i am not able to make any changes.
In your fragment, override onHiddenChanged(...) method:
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
Log.d(TAG, ((Object) this).getClass().getSimpleName() + " is NOT on screen");
}
else
{
Log.d(TAG, ((Object) this).getClass().getSimpleName() + " is on screen");
}
}
Hope this work for you!
Without touching the Activity or Fragment code and assuming you don't know the tag or layout it is placed in, there is very little that you can do. The best that I can see is that you could get the FragmentManager in ActivityResumed and ActivityStopped callbacks (because here you have an Activity reference) and apply a BackstackChangedListener. This assumes that you use the backstack when changing between fragments.
The issue with what you are asking is that you want lifecycle callbacks for Fragments on the Application level when you have no control over the middle men, the Activities which are already starved for Fragment callbacks. They do most everything through their FragmentManager, and propagate their own lifecycle callbacks down to the Fragments so that the fragments will behave appropriately. The onResume and onPause callbacks in fragments only occur when they are first created or when the Activity experiences those callbacks. There is only one lifecycle callback for Fragments in Activities, onAttachFragment, which if you could override, would give you references to the Fragments that are attached to the Activity. But you said you can't change the Activity or the Fragment, and you want to know when the Fragments are shown.
So if you don't use the backstack, I don't think there's a way to do what you want.
For putting Fragments inside Activity i use SlidingTabLayout which Google uses. Inside it you have ViewPager and some Adapter to populate many Fragments. First of all you have to put this and this files in your project. Then here there is good tutorial for how you can implement SlidingTabLayout.
1) After you have implemented SlidingTabLayout in your Activity, you can detect when and which Fragment becomes visible from Activity:
mSlidingTabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Do nothing
}
#Override
public void onPageSelected(int position) {
if (position == 0) {
//Whenever first fragment is visible, do something
} else if (position == 1) {
//Whenever second fragment is visible, do something
} else if (position == 2) {
//Whenever third fragment is visible, do something
} else if (position == 3) {
//Whenever fourth fragment is visible, do something
}
}
#Override
public void onPageScrollStateChanged(int state) {
//Do nothing
}
});
2) You can detect if Fragment is visible from Fragment itself as i answered here, however this may get called before onCreateView() of Fragment, so check answer in the link:
#Override
public void setUserVisibleHint(boolean visible){
super.setUserVisibleHint(visible);
if (visible){
//when this Fragment is active, do something
}
}
3) You can change also change colors of indicators of each Tab like this from Activity:
mSlidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
if (position == 0) {
return getResources().getColor(R.color.orange);
} else if (position == 1) {
return getResources().getColor(R.color.redDimmed);
} else if (position == 2) {
return getResources().getColor(R.color.yellow);
} else if (position == 3) {
return getResources().getColor(R.color.green);
} else {
return getResources().getColor(R.color.redLight);
}
}
#Override
public int getDividerColor(int position) {
return getResources().getColor(R.color.defaultActionBarBg);
}
});
Use same way as activity
set flag in application class to check visiblity of fragment, use below code in fragment
#Override
public void onStart() {
super.onStart();
Log.e( "Fragment is visible", "Fragment is visible");
Application Class.isFragmentShow = true;
}
#Override
public void onPause() {
super.onPause();
Log.e("Fragment is not visible", "Fragment is not visible");
Application Class.isFragmentShow = false;
}
to communicate with fragment you have to call that activity in which fragment added then use below code
MainFragment fragment = (MainFragment) fragmentManager.findFragmentByTag("MainFragment");
fragment.setFilter();
Don't exist a default way to do, but you can make your own Callbacks, I made this and works fine, first need have a BaseFragment class where we'll handle all fragment events.
public class BaseFragment extends Fragment {
private String fragmentName;
private FragmentLifecycleCallbacks listener;
public void registerCallBacks(String fragmentName){
// handle the listener that implement 'MyApp' class
try{
listener = (FragmentLifecycleCallbacks) getActivity().getApplication();
} catch (ClassCastException e) {
throw new ClassCastException("Application class must implement FragmentLifecycleCallbacks");
}
// set the current fragment Name for the log
this.fragmentName = fragmentName;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if(listener!=null) {
listener.onAttachFragment(fragmentName);
}
}
#Override
public void onResume() {
super.onResume();
if(listener!=null) {
listener.onResumeFragment(fragmentName);
}
}
#Override
public void onStop() {
super.onStop();
if(listener!=null) {
listener.onStopFragment(fragmentName);
}
}
// 'MyApp' class needs implement this interface to handle all the fragments events
public interface FragmentLifecycleCallbacks{
void onStopFragment(String fragmentName);
void onResumeFragment(String fragmentName);
void onAttachFragment(String fragmentName);
}}
On 'MyApp' class implement the interface of BaseFragment
public class MyApp extends Application implements BaseFragment.FragmentLifecycleCallbacks{
public static final String TAG = MyApp.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStopFragment(String fragmentName) {
Log.d(TAG, fragmentName + " is NOT on screen");
}
#Override
public void onResumeFragment(String fragmentName) {
Log.d(TAG, fragmentName + " is on screen");
}
#Override
public void onAttachFragment(String fragmentName) {
Log.d(TAG, fragmentName + " is attached to screen");
}}
And now each Fragment that you have need extends 'BaseFragment' and register to the global listener
public class FragmentA extends BaseFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_simple, container, false);
// here register to the global listener
registerCallBacks(FragmentA.class.getName());
return rootView;
}}
Hope this helps!
Intercept onWindowFocusChanged() in the activity and propagate that to the interested fragment.
Try this
private Boolean isFragmentVisible()
{
if(getFragmentManager().findFragmentByTag("TAG") != null && getFragmentManager().findFragmentByTag("TAG").isVisible())
{
//The fragment is visible
return true;
}
return false;
}
Alternative way
private Boolean isFragmentVisible()
{
return getFragmentManager().findFragmentByTag("TAG") != null && getFragmentManager().findFragmentByTag("TAG").isVisible();
}
You can know the following with the built in method called "onActivityCreated(Bundle)" this method tells that the fragment has been created thus you get to know that the fragment appears on the screen Click here for reference
Hope it helps
I've looked through what's available without using a base Fragment or Activity class but couldn't find any. I've made an implementation that provides basic (onAdded / onRemoved) functionality for all fragments in your application. It is certainly possible to extend it to report the current state of the fragment (onAttach, onResume, onPause, onDetach, ...).
You can find the code along with a sample here: https://github.com/Nillerr/FragmentLifecycleCallbacks
It works both for non-support library Fragments and support library Fragments through different implementations. The support library class is safer to use and should perform better, because the non-support one uses Reflection to access the fragments, while the support library FragmentManager includes a getFragments() method.
If you are setting a Fragment to your View, you probably have a container where it will be shown. Given that this container is, say, a FrameLayout with id R.id.container, you can do that:
Fragment f = fragmentManager.findFragmentById(R.id.container);
if (f instanceof YourFragment) {
// TODO something when YourFragment is ready
}
Does this interface provide anything helpful to you?
https://github.com/soarcn/AndroidLifecyle/blob/master/lifecycle/src/main/java/com/cocosw/lifecycle/FragmentLifecycleCallbacks.java
It sounds like your best bet if you can't override the Fragment's own onResume() method is to create your own interface that extends ActivityLifecycleCallbacks, then put your logging code in the onFragmentResumed(Fragment yourFragment) method.
You can get a pointer to the Fragment by doing something like this:
int yourFragmentId = 0; //assign your fragment's ID to this variable; Fragment yourFragment.getId();
FragmentManager fm = activity.getFragmentManager();
Fragment f = fm.findFragmentById(yourFragmentId);
whereever u want to check if fragment is visible or not.. just check isMenuVisible() value.
this is fragment's method which i used to check visible fragment when i have to fire some http request from viewpager selected Item.
hope this helps.
in my case i was using this method in onActivityCreated().
In you fragment override method setMenuVisibility If you are using ViewPager and are swiping from left and right, this method is called when the visivility of the fragment gets changed.
Here is a sample from my project
public abstract class DemosCommonFragment extends Fragment {
protected boolean isVisible;
public DemosCommonFragment() {
}
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
isVisible = menuVisible;
// !!! Do Something Here !!!
}
}
Animation listener
I have NOT checked all use cases and there is an unhandled exception. You can play around with it to fit your use case. Please feel free to comment your opinions or use cases it did not solve.
NOTE: You can add fragmentWillDisappear and fragmentDidDisappear by handling for enter in onCreateAnimation.
Parent Fragment:
public class BaseFragment extends Fragment {
private Animation.AnimationListener animationListener;
private void setAnimationListener(Animation.AnimationListener animationListener) {
this.animationListener = animationListener;
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
fragmentWillAppear(animation);
}
#Override
public void onAnimationEnd(Animation animation) {
fragmentDidAppear(animation);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
#Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
AnimationSet animSet = new AnimationSet(true);
Animation anim = null;
try {
anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
} catch (Exception error) {
}
if (anim != null) {
anim.setAnimationListener(animationListener);
animSet.addAnimation(anim);
}
return animSet;
}
public void fragmentDidAppear(Animation animation) {
}
public void fragmentWillAppear(Animation animation) {
}
}
Child Fragment:
class ChildFragment extends BaseFragment {
#Override
public void fragmentDidAppear(Animation animation) {
super.fragmentDidAppear(animation);
}
#Override
public void fragmentWillAppear(Animation animation) {
super.fragmentWillAppear(animation);
}
}

Android AsyncTask re-runs when activity is opened

In my App the user has to login.
They open the app on the login page
They enter email/password and hit login
A LoadingScreenActivity is opened that has a swirly circle and is running an AsyncTask that goes to my database and retrieves all the users info
After the AsyncTask is completed it starts an intent to launch MainPageActivity.
There are two problems with this at the moment:
If the user logs in and then goes to the home screen while the app loads the MainPageActivity will open as soon as it is ready (on top of the existing home page) even though the app has been minimised
If the user logs in and then goes to the home screen while the app loads and then returns to the loading screen the AsyncTask will complete twice over
For problem 1. At the moment my onPostExecute() method in LoadingScreenActivity looks like this:
#Override
public void onPostExecute() {
//open the main page
Intent mainPage = new Intent(getApplicationContext(), MainPageActivity.class);
mainPage.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mainPage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK );
startActivity(mainPage);
}
Is there a way I could detect in this method if the main page activity should be opened yet?
For problem 2. I've hit a complete road block on this, is there a way to detect if the activity has simply been re opened rather than started for the first time? I'd really appreciate any tips on this, I'm quite new to android so I'm not even convinced an Async task is the way to go with this.
Thanks for your time
LoadingScreenActivity.java
public class LoadingScreenActivity extends Activity implements TaskFragment.TaskCallbacks {
private static final String TAG_TASK_FRAGMENT = "task_fragment";
private TaskFragment mTaskFragment;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag(TAG_TASK_FRAGMENT);
// If the Fragment is non-null, then it is currently being
// retained across a configuration change.
if (mTaskFragment == null) {
mTaskFragment = new TaskFragment();
fm.beginTransaction().add(mTaskFragment, TAG_TASK_FRAGMENT).commit();
}
setContentView(R.layout.loading_screen);
ActionBar actionBar = getActionBar();
actionBar.hide();
TextView title = (TextView) findViewById(R.id.loading_title);
TextView progress = (TextView) findViewById(R.id.loading_progress);
title.setText(R.string.app_name);
progress.setText("Loading your info");
}
#Override
public Context onPreExecute() {
return getApplicationContext();
}
#Override
public void onProgressUpdate(int percent) {
}
#Override
public void onCancelled() {
Intent login = new Intent(getApplicationContext(), LoginActivity.class);
login.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(login);
finish();
}
#Override
public void onPostExecute() {
//open the main page
Intent mainPage = new Intent(getApplicationContext(), MainPageActivity.class);
mainPage.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mainPage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK );
startActivity(mainPage);
}
}
and TaskFragment.java
public class TaskFragment extends Fragment {
static interface TaskCallbacks {
Context onPreExecute();
void onProgressUpdate(int percent);
void onCancelled();
void onPostExecute();
}
private TaskCallbacks mCallbacks;
private DummyTask mTask;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (TaskCallbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retain this fragment across configuration changes.
setRetainInstance(true);
// Create and execute the background task.
mTask = new DummyTask();
mTask.execute();
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class DummyTask extends AsyncTask<Void, Integer, Void> {
Context context;
boolean running = true;
#Override
protected void onPreExecute() {
if (mCallbacks != null) {
context = mCallbacks.onPreExecute();
}
}
#Override
protected Void doInBackground(Void... ignore) {
//Get the current thread's token
synchronized (this)
{
if(running){
DatabaseHandler dbHandler = new DatabaseHandler(context);
dbHandler.populateSQLiteDatabase();
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... percent) {
if (mCallbacks != null) {
mCallbacks.onProgressUpdate(percent[0]);
}
}
#Override
protected void onCancelled() {
if (mCallbacks != null) {
mCallbacks.onCancelled();
}
}
#Override
protected void onPostExecute(Void ignore) {
if (mCallbacks != null) {
mCallbacks.onPostExecute();
}
}
}
}
in your activity in the manifest just add android:configChanges="keyboardHidden|orientation|screenSize"
and in the activity implement this
#Override
public void onConfigurationChanged(Configuration newConfig) {
};
I'm afraid, i don't really understand your first problem.
About the second one, there are a couple of ways depending on your minimum API level. Starting from API 14 you may register ActivityLifecycle Callbacks inside an Android Application. To do this, i would recommend:
Inherit Android application with a custom one
Replace the Android application in your manifest
inside your custom application register itself as activity lifecycle listener
inside the abstract methods you get the instance of the currently applying activity (may safe object.name() in a String)
depending on your handling you may safe a boolean value or whatever to identify the behaviour
methods inside your custom application are accessible by casting (MyCustomApplication)getApplication()
Heres a snippet:
package com.example.preferencestest;
import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
public class MyCustomApplication extends Application implements ActivityLifecycleCallbacks {
private String storedActivity;
private Boolean doOrNot = false;
public MyCustomApplication() {}
public Boolean getDoOrNot() { return doOrNot;}
public void setDoOrNot(Boolean doOrNot) { this.doOrNot = doOrNot; }
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
// these two are the most important ones since they will be fired everytime
#Override
public void onActivityResumed(Activity activity) {
if (activity.getClass().getName().equals(storedActivity)) {
doOrNot = true;
}
}
#Override
public void onActivityPaused(Activity activity) {
storedActivity = activity.getClass().getName();
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { }
#Override
public void onActivityStarted(Activity activity) { }
#Override
public void onActivityStopped(Activity activity) { }
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) { }
#Override
public void onActivityDestroyed(Activity activity) { }
}
inside your Manifest you MUST declare this new Applicationclass like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.preferencestest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="21" />
<application
android:name="com.example.preferencestest.MyCustomApplication"
{...}
Then inside your Activity you may do this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Boolean whatToDo = ((MyCustomApplication)getApplication()).getDoOrNot();
}
Using onConfigurationChanged has a couple of disadvantages. There are a couple of actions (placing device in dock, turning display and so on) which restart the Activity. You should rather save the current state of the Activity with
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
}

Categories

Resources