In my application i am using some fragments, in a viewpager.
I want to show a dialog in a fragment like this:
final Dialog dialog = new Dialog(activity, R.style.DialogTheme);
dialog.show();
The activity is set in the onCreateView like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
activity = getActivity();
}
This is working perfectly, but in some cases like if the app goes in background, and the user comes back to the app, i got an error "Fragment not attached to activity" in the line "dialog.show()".
So to prevent this error i use this:
if(!activity.isFinishing())
dialog.show();
else
Toast.makeText(activity, "Error", Toast.LENGTH_SHORT).show();
I think this is definitly not the best way...
Is there maybe a solution like reloading the app if the activity isFinishing or even a better solution?
override onAttach method
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof YourActiivty) {
//here is your code
} else {
}
}
public class MyFragment extends Fragment
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
...
}
}
Try to use DialogFragment rather than showing dialog by Dialog class, it will give you more stable view ,just extend your class by "DialogFragment"
public class DemoDialogFragment extends DialogFragment{
public DemoDialogFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_demo_dialog, container, false);
-----------
return rootView;
}
and make function in you activity for calling it
public void showDialogFrag(DialogFragment dialogFragment, String tag) {
dialogFragment.show(getSupportFragmentManager(), tag);
}
Then call this function by this from any fragment
((MainActivity) getActivity()).showDialogFrag(new DemoDialogFragment(), Constant.FragmentTags.DemoDialogFragment);
Related
I want to detect whether the DialogFragment is opened from an Activity or Fragment. Because the calling Activity or Fragment will have an Interface attached for a listener.
if Activity is used to show the dialog:
(inside DialogFragment I will write)
listener = (MyListener) getActivity();
else if Fragment is calling the dialog:
listener = (MyListener) getParentFragment;
So, I need to detect who is calling the dialog fragment!
If you ask me to edit your code then do this.
void showDialog() {
DialogFragment newFragment = new MyAlertDialogFragment();
newFragment.setFromActivity(true); pass here.
newFragment.show(getFragmentManager(), "dialog");
}
In your DialogFragment
public static class MyAlertDialogFragment extends DialogFragment {
boolean isFromActivity;
public void setFromActivity(boolean isFromActivity){
this.isFromActivity = isFromActivity;
}
}
If you ask me a suggestion - Pass listener instead of checking from Activity or Fragment.
You should do common code by using setters, so that in future you can just pass listener.
DialogFragment newFragment = new MyAlertDialogFragment();
newFragment.setListener(this); // or use anonymous deriving like new Listener()...
I am using the below style for my question, posting as an answer because it might help someone.
public MyDialog extends DialogFragment{
private MyListener listener;
public static MyDialog newInstance(MyListener callback){
MyDialog dialog = new MyDialog();
dialog.listener = callback;
return dialog;
}
//rest of the Dialog code such as onCreate() etc..
}
And calling from Any Activity or Fragment
ACTIVITY
public MyActivity extends AppCompatActivity implements MyListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
MyDialog dialog = MyDialog.newInstance(this);
dialog.show(getSupportFragmentManager, "TAG");
}
}
FRAGMENT
public MyFragment extends Fragment implements MyListener{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.my_frag_layout, container, false);
MyDialog dialog = MyDialog.newInstance(this);
dialog.show(getChildFragmentManager, "TAG");
return view;
}
}
Please comment if there is any possiblity of error or conditions where it can crash. Thank you!
I know how to show full screen activity but it is not working in fragment activity ?
public class Dialog extends Fragment {
public Dialog() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.dialog, container, false);
}
}
Try to use DialogFragment:
public class FullScreenDialogFragment extends DialogFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.dialog, container, false);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
return dialog;
}
#Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
}
}
In your question you have asked how to show full-screen fragment activity?
If you know how to make how to make an activity to full screen. You have to use the same way to make the FragmentActivity full screen. Because FragmentActivity is a subclass of Activity.
↳ android.app.Activity
↳ android.support.v4.app.FragmentActivity
Also in your question, The class you have included is Fragment, not FragmnetActivity.
If you need to make your fragment full screen you have to make your hosting activity fullscreen.
use getActivity() method to get hosting activity from the fragment. Then you can make the fragment fullscreen.
The answer by #shmakova worked for me, but then my colleague pointed out a simpler solution. It is enough to have the dialog's style inherit from a style, whose name ends with NoTitleBar.Fullscreen and add a windowNoTitle element. For example:
In my Dialog:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AppCompatDialog(getActivity(), R.style.MyDialogStyle);
}
in src/main/res/values/styles.xml:
<style name="MyDialogStyle" parent="#android:style/Theme.Light.NoTitleBar.Fullscreen">
<item name="windowNoTitle">true</item>
</style>
There are several advantages of such an approach: you don't have to override onCreateDialog and can have multiple styles.xml instances depending on device features. For example, you can have your dialog extend to full screen only on the smaller screens.
try this solution
public class setWallpaperFragment extends DialogFragment {
public setWallpaperFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int theme = android.R.style.Theme_Black_NoTitleBar_Fullscreen;
setStyle(DialogFragment.STYLE_NO_TITLE,theme);
}
The action of back button is bring back to the previous page.
How to change the action of back button in Android fragment, for example:
if( click back button ) then
Toast.maketext("text");
my code is :
public class Rechercher extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
/* pour creer le fragment */
view = inflater.inflate(R.layout.rechercheavance, container, false);
return view;
}
}
From the Activity, override the onBackPressed() method for custom back press action. Hold an instance of the fragment when you attach it and use a public method in the fragment for doing something from the fragment by calling it from the onBackPressed() method.
Activity
SomeFragment fragment;
#Override
public void onCreate(Bundle savedInstanceState) {
...
//Create the fragment instance
fragment = new SomeFragment();
//Now add the fragment to the layout
}
...
#Override
public void onBackPressed() {
//Called when back pressed
fragment.doSomething();
}
And in the Fragment define the method doSomething
public void doSomething() {
//custom action
}
I have setup a very simple test project https://github.com/ArtworkAD/ViewPagerDialogTest to evaluate following situation: the main activity has a view pager which hosts a single fragment using support fragment manager:
public class MainActivity extends AppCompatActivity {
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
// ...
tabLayout.setupWithViewPager(viewPager);
}
#Override
protected void onResume() {
super.onResume();
MainActivity.CustomDialog dialog = (MainActivity.CustomDialog) getSupportFragmentManager().findFragmentByTag(MainActivity.CustomDialog.TAG);
if (dialog == null) {
new MainActivity.CustomDialog().show(getSupportFragmentManager().beginTransaction(), MainActivity.CustomDialog.TAG);
}
}
// ...
}
When the activity is resumed a dialog fragment is shown inside the main activity.
The single fragment inside the view pager is defined like this:
public class RootFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.root_fragment, container, false);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().add(R.id.root_frame, new FirstLevelFragment(), "ROOT").commit();
}
return root;
}
}
This root fragment allows us to stack other fragments on the "root_frame". So we stack another and another:
public class FirstLevelFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setRetainInstance(true);
View root = inflater.inflate(R.layout.first_level_fragment, container, false);
root.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SecondLevelFragment f = (SecondLevelFragment) getActivity().getSupportFragmentManager().findFragmentByTag("NESTED");
if (f == null) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.root_frame, new SecondLevelFragment(), "NESTED").addToBackStack(null).commit();
}
}
});
return root;
}
public static class SecondLevelFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setRetainInstance(true);
return inflater.inflate(R.layout.second_level_fragment, container, false);
}
}
}
This works great! The stacking idea is taken from https://stackoverflow.com/a/21453571/401025 . However when dialog is shown and the users goes to the second level fragment and rotates the screen I get following exception:
E/AndroidRuntime: java.lang.RuntimeException: Unable to start activity
ComponentInfo{de.azzoft.viewpagerdialogtest/de.azzoft.viewpagerdialogtest.MainActivity}:
java.lang.IllegalArgumentException: No view found for id 0x7f0c0083
(de.azzoft.viewpagerdialogtest:id/root_frame) for fragment
SecondLevelFragment{15c0db38 #0 id=0x7f0c0083 NESTED}
E/AndroidRuntime: Caused by: java.lang.IllegalArgumentException: No
view found for id 0x7f0c0083
(de.azzoft.viewpagerdialogtest:id/root_frame) for fragment
SecondLevelFragment{15c0db38 #0 id=0x7f0c0083 NESTED}
Full stack trace: https://github.com/ArtworkAD/ViewPagerDialogTest/blob/master/README.md
Without the dialog appearing everything works great. You can test it by downloading the test project.
It seems that the dialog, which is actually a fragment, messes up fragment hierarchy when it is added to the activity. Any ideas how to fix this?
It is important that the second fragment is retained.
No view found for id 0x7f0c0083 (de.azzoft.viewpagerdialogtest:id/root_frame) for fragment SecondLevelFragment
When Activity recreates on rotate, the Activity FragmentManger tries to add the SecondLevelFragment into R.id.root_frame . But the root_frame view is not in Activity layout, its in FirstLevelFragment layout. Thats why the app crashes.
You have to make two changes to fix this issue.
Add the FirstLevelFragment into the RootFragment using the getChildFragmentManager
getChildFragmentManager().beginTransaction().add(R.id.root_frame, new FirstLevelFragment(), "ROOT").commit();
Add the SecondLevelFragment using FragmentManager
getFragmentManager().beginTransaction().add(R.id.root_frame, new SecondLevelFragment(), "NESTED").addToBackStack(null).commit();
Finally remove the setRetainInstance from FirstLevelFragment and SecondLevelFragment as nested fragments doesn't required to set retain.
If you need to pop back the SecondLevelFragment on back press you need to pass the back press the event to RootFragment and pop from back stack.
Override the back press on activity
#Override
public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.viewpager);
if(fragment instanceof RootFragment){
boolean handled = ((RootFragment)fragment).onBackPressed();
if(handled){
return;
}
}
super.onBackPressed();
}
And handle the back press on RootFragment
public boolean onBackPressed() {
int count = getChildFragmentManager().getBackStackEntryCount();
if(count > 0){
getChildFragmentManager().popBackStackImmediate();
return true;
}
return false;
}
I created a Pull request to your repository . please check
https://github.com/ArtworkAD/ViewPagerDialogTest/pull/1
Let me know if any questions.
If you override onDismiss so resolved crash. enjoy it.
#Override
protected void onResume() {
super.onResume();
DialogFragment dialog = (DialogFragment) getSupportFragmentManager().findFragmentByTag(TAG);
if(dialog == null){
CustomDialog.newInstance().show(getSupportFragmentManager(), TAG);
}
}
public static class CustomDialog extends DialogFragment {
public static CustomDialog newInstance() {
CustomDialog d = new CustomDialog();
return d;
}
#Override
public void onDismiss(DialogInterface dialog) {
// super.onDismiss(dialog);
Toast.makeText(getActivity(), "onDismiss", Toast.LENGTH_LONG).show();
}
#Override
public void onCancel(DialogInterface dialog) {
// super.onCancel(dialog);
Toast.makeText(getActivity(), "onCancel", Toast.LENGTH_LONG).show();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Dialog");
builder.setMessage("This is a message!");
builder.setPositiveButton("Okay", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(getActivity(), "onClick", Toast.LENGTH_LONG).show();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(getActivity(), "onClick", Toast.LENGTH_LONG).show();
}
});
return builder.show();
}
}
If you want to keep the state of your Fragments you should use a FragmentStatePagerAdapter.
From the docs:
Implementation of PagerAdapter that uses a Fragment to manage each
page. This class also handles saving and restoring of fragment's
state.
If you use this you can also remove the setRetainInstance(true) calls.
Well, I had downloaded your Test app and it seems that I have fixed the problem.
In your FirstLevelFragment class, comment the following line
//if (nestedNestedFragment == null) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.root_frame, new SecondLevelFragment(), "NESTED").addToBackStack(null).commit();
//}
And
Comment setRetainInstance(true); in SecondLevelFragment
I think you missed setContentView() in onCreate() of your Activity. See your Fragment can not be added without a View hierarchy. Your Fragment is hosted by an activity. So you need to set the content to the activity first.
Hope this Helps,
Thanks.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Android fragments setRetainInstance(true) not works (Android support library)
I wrote a simple test project, but I cant understand why I always receive savedInstanceState = null in lifecycle methods onCreate, onCreateView and onActivityCreated. I change the screen orientation, see the log, but state not saved.
Tell me please where is my mistake.
Thanks.
The code of fragment class is:
public class TestFragment extends Fragment {
private String state = "1";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (savedInstanceState != null) {
//never works
state = savedInstanceState.getString("state");
}
//always prints 1
Toast.makeText(getActivity(), state, Toast.LENGTH_SHORT).show();
return inflater.inflate(R.layout.fragment_layout, container, false);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("state", "2");
Log.e("", "saved 2");
}
}
EDIT
When i try to use setRetainInstance i have no result again((( I change a state to 2 using btn1, but after changing orientation i see 1 when pressing on btn2. Help please(
public class TestFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
private String state = "1";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, container, false);
//button for changing state
((Button)view.findViewById(R.id.button1)).setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
state = "2";
}
});
//button for showing state
((Button)view.findViewById(R.id.button2)).setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
Toast.makeText(getActivity(), state, Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
I have seen the same issue. But you can save the instate state in an other way, thanks to the method setRetainInstance(true), all your class data are saved automatically.
#Override
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
EDIT
Try to also add these params when you declare your activities :
<activity
android:name="MyActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />