I have two reuse fragments, and the second on is a flutter fragment, which behave strange.
above Android API 29, flutter fragment will render above first fragment after the detail activity pop out of stack .
under Android API 29, flutter fragment always render above all views in the main activity.
I create this repository to reproduce this error.
This unsolved question is similar to mine.
this code shows how I reuse fragments
private void switchTo(String tag) {
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
if (tag.equals("home")) {
fragmentTransaction.show(homeFragment);
fragmentTransaction.hide(notificationsFragment);
} else {
fragmentTransaction.show(notificationsFragment);
fragmentTransaction.hide(homeFragment);
}
fragmentTransaction.commitNowAllowingStateLoss();
}
this is where flutter fragment add to the view
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
FragmentManager fragmentManager = getChildFragmentManager();
if (mRepGoalsFlutterFragment1 == null) {
mRepGoalsFlutterFragment1 = FlutterFragment.withNewEngine()
.build();
fragmentManager
.beginTransaction()
.add(R.id.card_view7,
mRepGoalsFlutterFragment1,
TAG_REP_GOALS_FLUTTER_FRAGMENT_1)
.commit();
}
return inflater.inflate(R.layout.fragment_notifications, container, false);
}
In my Fragment, I have to detachFlutterEngine myself to fix this problem.
private FlutterView myFlutterView;
private boolean isFlutterHidden = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
myFlutterView = FlutterBoostUtils.findFlutterView(view);
return view;
}
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
isFlutterHidden = hidden;
updateFlutterViewHidden();
}
#SuppressLint("VisibleForTests")
void updateFlutterViewHidden() {
if (myFlutterView == null) return;
if (isFlutterHidden) {
myFlutterView.setVisibility(View.GONE);
} else {
myFlutterView.setVisibility(View.VISIBLE);
}
}
#Override
public void onResume() {
super.onResume();
updateFlutterViewHidden();
}
Combine your posts with Github issue(https://github.com/flutter/flutter/issues/59968),the solution is create self class extends FlutterFragment, get flutterSurfaceView in the onFlutterSurfaceViewCreated.
private FlutterSurfaceView flutterView;
#Override
public void onFlutterSurfaceViewCreated(#NonNull FlutterSurfaceView flutterSurfaceView) {
super.onFlutterSurfaceViewCreated(flutterSurfaceView);
LogUtils.d(TAG, "onFlutterSurfaceViewCreated开始");
this.flutterView = flutterSurfaceView;
LogUtils.d(TAG, "onFlutterSurfaceViewCreated结束");
}
Then setVisibility in onResume.
#SuppressLint("解决FlutterFragment切换到前台显示的问题")
void updateFlutterViewVisibility() {
if (flutterView == null) {
return;
}
if (isFlutterHidden) {
flutterView.setVisibility(View.GONE);
} else {
flutterView.setVisibility(View.VISIBLE);
}
}
#Override
public void onResume() {
LogUtils.d(TAG, "onResume开始");
super.onResume();
updateFlutterViewVisibility();
LogUtils.d(TAG, "onResume结束");
}
#Override
public void onHiddenChanged(boolean hidden) {
LogUtils.d(TAG, "onHiddenChanged开始");
super.onHiddenChanged(hidden);
isFlutterHidden = hidden;
updateFlutterViewVisibility();
LogUtils.d(TAG, "onHiddenChanged结束");
}
Create your self class extends FlutterFragment like this:
FlutterFragment.CachedEngineFragmentBuilder(
YourFlutterFragment::class.java,
YourFlutterFragmentEngineId
)
.shouldAttachEngineToActivity(false)
.build<YourFlutterFragment>()
Related
Inside my MainActivity (Demo) I add FragmentDemo 1 to backstack. Inside this fragmentDemo 1, pressing a button opens a new FragmentDemo 2, where I have an edit text. On pressing the button on this second fragment, I want to remove it from backstack and send the data from editText back to FragmentDemo 1.
I am using a listener on Fragment 2, and implementing the methods, but when I run the code I have the following message. java.lang.ClassCastException: com.example.teacherapp.activities.Demo#5630fb7must implement Listener
Demo (Main Activity)
public class Demo extends AppCompatActivity implements FragmentInterface {
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
if (savedInstanceState == null) {
addFragment(new FragmentDemo1());
}
}
#Override
public void onMyFragment(Fragment fragment) {
addFragment(fragment);
}
private void addFragment(Fragment fragment){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.demo_container,fragment)
.addToBackStack(null)
.commit();
}
}
FragmentInterface
public interface FragmentInterface {
void onMyFragment(Fragment fragment);
}
FragmentDemo 1
public class FragmentDemo1 extends Fragment implements FragmentInterface, FragmentDemo2.Fragment2CallBack {
Button btnFrag1;
TextView tvFrag1;
public FragmentDemo1() {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_fragment_demo1, container, false);
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
btnFrag1 = view.findViewById(R.id.fragment1_button);
tvFrag1 = view.findViewById(R.id.fragment1_tv);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getFragmentManager();
btnFrag1.setText("Frag 1: " + String.valueOf(fm.getBackStackEntryCount()));
btnFrag1.setOnClickListener(v -> {
replaceFragment(new FragmentDemo2());
});
}
#Override
public void onMyFragment(Fragment fragment) {
replaceFragment(fragment);
}
private void replaceFragment(Fragment fragment) {
getFragmentManager().
beginTransaction().
replace(R.id.demo_container, fragment).
addToBackStack(null).
commit();
}
#Override
public void onDataSent(String myData) {
Toast.makeText(getContext(), "RECEIVED. "+myData, Toast.LENGTH_LONG).show();
}
}
FragmentDemo 2
public class FragmentDemo2 extends Fragment {
private Button btnFrag2;
private EditText etFrag2;
private Fragment2CallBack listener;
public FragmentDemo2(){}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_fragment_demo2,container,false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
btnFrag2=view.findViewById(R.id.fragment2_button);
etFrag2=view.findViewById(R.id.fragment2_et);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm=getFragmentManager();
btnFrag2.setOnClickListener(v->{
String info=etFrag2.getText().toString();
listener.onDataSent(info);
fm.popBackStack();
});
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try{
listener=(Fragment2CallBack) context;
}catch (ClassCastException e){
throw new ClassCastException(context.toString()+"must implement Listener");
}
}
public interface Fragment2CallBack{
void onDataSent(String s);
}
}
The result expected is to have fragment 2 removed from backstack and open fragment 1, with received data from fragment 2.
Fragment Back Stack Example.
Refer this url https://www.dev2qa.com/android-fragment-back-stack-example/
The Problem in your existing code
The Context you try to use in FragmentDemo2 is of Demo activity (not of FragmentDemo1) so you can not type cast it to listener when you are trying to attach
If you want to achieve the same goal with existing code, follow below step
1) Expose API from FragmentDemo2 that will allow to set Listener of type Fragment2Callback
public void setListener(Fragment2Callback li) {listener = li;}
2) From FragmentDemo1, when you create FragmentDemo2 instance, you also need to set itself as listener to FragmentDemo2
FragmentDemo2 frg = new FragemtDemo2()
frg.setListener(this);
replaceFragment(frg);
3) Then replaceFragment() from FragmentDemo1
4) remove casting of listener from onAttach() inside FragmentDemo2
So now you have FragmentDemo1 as listener inside FragmentDemo2, which you can use to communicate to fragmentDemo1
I hope this information help you
So basically, i have an activity called (Profile Activity) and two fragments connected to it (Profile view and profile edit fragment). Since im completely new with android studio, java language and fragments, im trying to place both fragments into activity but in a way that only profile view fragment is shown. Edit profile fragment needs to be hidden. Im using next part of the code:
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileViewFragment).commit();
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
I already tried something with "hide" and "show", but with no success. I have imported "android.support.v4.app.FragmentManager;" Thank you.
EDIT:
Profile activity after implementing new code:
public class ProfileActivity extends AppCompatActivity implements ProfileViewFragment.ProfileViewListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
//ovo ispod je za proslijedivanje iz activita u fragment
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
ProfileViewFragment profileViewFragment = new ProfileViewFragment();
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileViewFragment.setArguments(getIntent().getExtras());
profileEditFragment.setArguments(getIntent().getExtras());
//getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileViewFragment).commit();
//getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileViewFragment).commit();
//FragmentManager fm=getSupportFragmentManager();
//fm.beginTransaction().setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).show(new ProfileViewFragment()).commit();
//fm.beginTransaction().setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).show(new ProfileEditFragment()).commit();
//-----------------------------------
}
#Override
public void onOpenProfileEditor() {
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileEditFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileEditFragment).commit();
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof ProfileViewFragment) {
ProfileViewFragment profileFragment = (ProfileViewFragment) fragment;
profileFragment.setListener(this::onOpenProfileEditor);
}
}
}
Profile view fragment with new code:
public class ProfileViewFragment extends Fragment {
private Unbinder unbinder;
//novi kod sa stacka
private ProfileViewListener listener;
//-------------
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
FragmentProfileViewBinding viewBinding=DataBindingUtil.inflate(inflater, R.layout.fragment_profile_view, container, false);
View view=viewBinding.getRoot();
unbinder = ButterKnife.bind(this, view);
UserModel user = (UserModel) getArguments().get(ModelEnum.UserModel.name());
//viewBinding povezuje fragment i xml (proslijeduje user)
viewBinding.setUser(user);
//viewBinding.setUserGender(user);
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
// #OnClick(R.id.btn_change_settings)
// public void changeSettings(){
//getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, new ProfileEditFragment()).commit();
// }
#Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
//ISPOD JE NOVI KOD SA STACK OVERFLOWA
public interface ProfileViewListener{
void onProfileEditor();
}
public void setListener(ProfileViewListener listener) {
this.listener = listener;
}
#OnClick(R.id.btn_change_settings)
public void onEdit(View view){
if(listener!=null){
onOpenProfileEditor();
}
}
}
Instead of
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
It must be
getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileEditFragment).commit();
This will replace your fragment, instead of adding it.
Please, also note that you must call "add" for the first time and use "replace" afterwards.
You may find more about fragments here: https://developer.android.com/training/basics/fragments/fragment-ui
EDIT
For the new issue you have outlined, the solution is to "report" you activity that an event had happened, so it can take action. Here is how to do that.
First, we need an interface (you can add it inside you Profile fragment) and to link the activity to our fragment, if it implements that interface.
public class ProfileViewFragment extends Fragment {
...
...
private ProfileViewListener listener;
...
...
#OnClick(R.id.btn_change_settings)
public onEdit(View view) {
// If there is anyone listening, report that we need to open editor
if (listener != null) {
listener .onOpenProfileEditor();
}
}
public void setListener(ProfileViewListener listener) {
this.listener = listener;
}
// The interface
public interface ProfileViewListener {
void onOpenProfileEditor();
}
}
And in the class, we need to implement the interface and subscribe as a listener.
public class ProfileActivity extends AppCompatActivity implements ProfileViewFragment.ProfileViewListener {
...
...
#Override
public void onOpenProfileEditor() {
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileEditFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager()
.beginTransaction
.replace(R.id.profile_fragment, profileEditFragment)
.commit();
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof ProfileViewFragment) {
ProfileViewFragment profileFragment = (ProfileViewFragment) fragment;
profileFragment.setListener(this);
}
}
}
You may find more detail on Activity-Fragment communication here - https://developer.android.com/training/basics/fragments/communicating
Below is the MainActivity class that I'm using. The code checks to see if the phone is in landscape or portrait. If it's in portrait, it will show the main fragment in the main activity only (the main fragment is a static fragment in the main_activity.xml file). Then if a "Recipe" is clicked it will open a detail activity with its own fragment. If the phone is in landscape mode, it will show the main fragment and the detail fragment side by side. Everything works perfectly fine however when I follow the procedure below I get a white screen instead of the main activity:
Procedure:
Switch to landscape
Switch back to portrait
Choose an item and wait for the detail activity to open
Press back
Here instead of the main activity window I get a white screen
If I don't switch to landscape and just start with the portrait mode everything is fine. It seems like switching to landscape does something that causes the problem and I can't figure out what. Any tip on what's going on or where to look would be much appreciated.
public class MainActivity extends AppCompatActivity implements RecipesFragment.OnRecipeClickListener {
private String RECIPE_PARCEL_KEY;
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RECIPE_PARCEL_KEY = getString(R.string.ParcelKey_RecipeParcel);
if (findViewById(R.id.linearLayoutTwoPane) != null) {
mTwoPane = true;
if (savedInstanceState == null) {
RecipeFragment recipeFragment = new RecipeFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.recipeFrameForTwoPane, recipeFragment)
.commit();
}
} else {
mTwoPane = false;
}
}
#Override
public void OnRecipeClick(Recipe recipe) {
if (mTwoPane) {
RecipeFragment recipeFragment = new RecipeFragment();
recipeFragment.setRecipe(recipe);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.recipeFrameForTwoPane, recipeFragment)
.commit();
} else {
Class destinationClass = DetailActivity.class;
Intent intentToStartDetailActivity = new Intent(this, destinationClass);
intentToStartDetailActivity.putExtra(RECIPE_PARCEL_KEY, recipe);
startActivity(intentToStartDetailActivity);
}
}
}
EDIT:
Adding RecipeFragment's code below:
public class RecipeFragment extends Fragment {
private Recipe mRecipe;
#BindView(R.id.tv_recipeName) TextView recipeNameTextView;
public RecipeFragment(){
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.recipe_fragment,container,false);
ButterKnife.bind(this,view);
if(mRecipe!=null) {
recipeNameTextView.setText(mRecipe.getName());
}else{
recipeNameTextView.setText(getString(R.string.messageSelectARecipe));
}
return view;
}
public void setRecipe(Recipe recipe){
mRecipe = recipe;
}
}
EDIT:
I followed #mt0s's advice and created different background colors for the fragments and activities and finally narrowed down the problem to a line in my recyclerview adapter code. My adapter code is below. Inside loadInBackground() on line URL url = new URL(getString(R.string.URL_RecipeJSON)); I get a Fragment RecipesFragment{96e9b6a} not attached to Activity exception. I don't understand why I'm getting this exception and what the best way to resolve this is. Have I placed the right code in the right fragment methods (ie OnCreate vs OnActivityCreated vs OnCreateView vs etc)?
public class RecipesFragment extends Fragment
implements RecipeAdapter.RecipeAdapterOnClickHandler,
LoaderManager.LoaderCallbacks<ArrayList<Recipe>> {
#BindView(R.id.rv_recipes) RecyclerView mRecyclerView;
private RecipeAdapter mRecipeAdapter;
private static final int LOADER_ID = 1000;
private static final String TAG = "RecipesFragment";
private OnRecipeClickListener mOnRecipeClickListener;
public RecipesFragment(){
}
public interface OnRecipeClickListener {
void OnRecipeClick(Recipe recipe);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.recipes_fragment, container, false);
ButterKnife.bind(this, view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecipeAdapter = new RecipeAdapter(this);
mRecyclerView.setAdapter(mRecipeAdapter);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void OnClick(Recipe recipe) {
mOnRecipeClickListener.OnRecipeClick(recipe);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
mOnRecipeClickListener = (OnRecipeClickListener) context;
} catch (ClassCastException e){
Log.e(TAG, "onAttach: Host activity class must implement OnRecipeClickListener.");
}
}
#Override
public Loader<ArrayList<Recipe>> onCreateLoader(int i, Bundle bundle) {
return new AsyncTaskLoader<ArrayList<Recipe>>(getActivity()) {
#Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad();
}
#Override
public ArrayList<Recipe> loadInBackground() {
String response;
ArrayList<Recipe> recipes = null;
try {
URL url = new URL(getString(R.string.URL_RecipeJSON)); //***I get an exception here***
response = NetworkUtils.getResponseFromHttpUrl(url, getActivity());
recipes = RecipeJsonUtils.getRecipeFromJson(getActivity(), response);
} catch (Exception e) {
Log.e(TAG, "loadInBackground: " + e.getMessage());
}
return recipes;
}
};
}
#Override
public void onLoadFinished(Loader<ArrayList<Recipe>> loader, ArrayList<Recipe> recipes) {
mRecipeAdapter.setRecipeData(recipes);
}
#Override
public void onLoaderReset(Loader<ArrayList<Recipe>> loader) {
}
}
I finally figured out the problem and the solution. The problem is that onStartLoading() in the AsyncTaskLoader anonymous class in RecipesFragment class gets called every time the fragment is resumed whether the enclosing Loader is called or not. This causes the problem. I need to have control over when onStartLoading() is being called and I only want it to be called if and only if the enclosing Loader is being initialized or restarted. As such, I destroyed the loader in onPause() of the fragment and restarted it in onResume(). Hence, I added the following code to the RecipesFragment class:
#Override
public void onPause() {
super.onPause();
getLoaderManager().destroyLoader(LOADER_ID);
}
#Override
public void onResume() {
super.onResume();
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
I also removed initLoader() from onCreate(). This way, every time the fragment is resumed (or created) onStartLoading() will be called. I tried this and it solves my problem.
When you switch from the landscape to portrait or the opposite the Android OS destroy your activity and recreate it again. this what probably trigger your problem
I am building an Android Application (minimum SDK Level 10). When the app is minimized and the user return later to it, the main menu shows buttons and images twice. It only happens when the user uses other apps in the middle, if it happens immediately then the menu is displayed correctly.
Here is the code of the fragment:
public class MainMenuFragment extends Fragment implements OnClickListener {
String mGreeting = "Hello, anonymous user (not signed in)";
public interface Listener {
public void onStartGameRequested(boolean hardMode);
public void onShowAchievementsRequested();
public void onShowLeaderboardsRequested();
public void onSignInButtonClicked();
public void onSignOutButtonClicked();
public void onPlayClicked();
public void onScoreClicked();
public void onFeedbackClicked();
}
Listener mListener = null;
boolean mShowSignIn = true;
View v;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(v==null){
v = inflater.inflate(R.layout.fragment_mainmenu, container, false);
final int[] CLICKABLES = new int[] {
R.id.show_leaderboards_button,
R.id.sign_in_button, R.id.sign_out_button, R.id.button_play, R.id.feedback
};
for (int i : CLICKABLES) {
v.findViewById(i).setOnClickListener(this);
}
}
else {
((ViewGroup)v.getParent()).removeView(v);
}
return v;
}
public void setListener(Listener l) {
mListener = l;
}
#Override
public void onStart() {
super.onStart();
//updateUi();
}
#Override
public void onResume() {
super.onResume();
updateUi();
}
#Override
public void onStop() {
super.onStop();
}
public void setGreeting(String greeting) {
mGreeting = greeting;
//updateUi();
}
void updateUi() {
try{
if (getActivity() == null) return;
getActivity().findViewById(R.id.sign_in_button).setVisibility(mShowSignIn ?
View.VISIBLE : View.GONE);
getActivity().findViewById(R.id.sign_out_button).setVisibility(mShowSignIn ?
View.GONE : View.VISIBLE);
}catch(Exception e){}
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.show_leaderboards_button:
mListener.onShowLeaderboardsRequested();
break;
case R.id.sign_in_button:
mListener.onSignInButtonClicked();
break;
case R.id.sign_out_button:
mListener.onSignOutButtonClicked();
break;
case R.id.feedback:
mListener.onFeedbackClicked();
break;
case R.id.button_play:
mListener.onPlayClicked();
break;
}
}
public void setShowSignInButton(boolean showSignIn) {
mShowSignIn = showSignIn;
updateUi();
}
}
Thank you in advance for any help. I cannot see what is called twice, and I have spent more hours than I would to admit.
EDIT 1: Trying Clint Deygoo solution. Defining View v inside the onCreate is not working neither. This is how I did it:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_mainmenu, container, false);
final int[] CLICKABLES = new int[] {
R.id.show_leaderboards_button,
R.id.sign_in_button, R.id.sign_out_button, R.id.button_play, R.id.feedback
};
for (int i : CLICKABLES) {
v.findViewById(i).setOnClickListener(this);
}
return v;
}
EDIT 2: SOLVED ISSUE. I removed updateUi() and it stopped happening. I am not sure about why it's working, but it is. Thank you all!
The problem is not in your onCreateView (You should use EDIT 1). It's about nested Fragments.
Raneez Ahmed posted a good answer here
Fragments within Fragments
I am adding a Map to a fragment with this code:
public class MapFragment : Fragment
{
private MapActivity map=null;
public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return new FrameLayout(Activity);
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
map = new MapView(Activity,"XXXXX-v0jt5Z-XXXXXX");
//HOW TO ADD THE VIEW HERE???
}
}
My question is, in Mono for Android how to I add the Map to the View.
Note: In Java I would write this:
((ViewGroup)getView()).addView(map);
Footnote: This example uses code from the Java MapFragment source code: https://github.com/commonsguy/cw-omnibus/blob/master/Maps/NooYawkFragments/src/com/commonsware/android/mapfrags/MapFragment.java
Maps can not be added to Fragments as is, they need a hosting environment.
Here's the solution for a MapFragment:
namespace BahaiResearch.com
{
public class MyMapFragment : Fragment
{
// FROM http://stackoverflow.com/questions/5109336/mapview-in-a-fragment-honeycomb
private static String KEY_STATE_BUNDLE = "localActivityManagerState";
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Bundle state = null;
if (savedInstanceState != null) {
state = savedInstanceState.GetBundle(KEY_STATE_BUNDLE);
}
mLocalActivityManager = new LocalActivityManager(Activity, true);
mLocalActivityManager.DispatchCreate(state);
}
public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//This is where you specify you activity class
Intent i = new Intent(Activity, typeof(SteamLocationMapActivity));
Window w = mLocalActivityManager.StartActivity("tag", i);
View currentView=w.DecorView;
currentView.Visibility = ViewStates.Visible;
currentView.FocusableInTouchMode = true;
((ViewGroup) currentView).DescendantFocusability = DescendantFocusability.AfterDescendants;
return currentView;
}
private LocalActivityManager mLocalActivityManager;
protected LocalActivityManager GetLocalActivityManager() {
return mLocalActivityManager;
}
public override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
outState.PutBundle(KEY_STATE_BUNDLE,mLocalActivityManager.SaveInstanceState());
}
public override void OnResume()
{
base.OnResume();
mLocalActivityManager.DispatchResume();
}
public override void OnPause()
{
base.OnPause();
mLocalActivityManager.DispatchPause(Activity.IsFinishing);
}
public override void OnStop()
{
base.OnStop();
mLocalActivityManager.DispatchStop();
}
}
}