I tried to create a ProgressFragment to be used in the whole application:
public class ProgressFragment extends Fragment {
private static final String KEY = "info";
private CustomProgressView mProgress;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(...);
mProgress = (CustomProgressView) root.findViewById(...);
mProgress.start();
if (getArguments() != null) {
mProgress.setText(getArguments().getString(KEY, ""));
}
return root;
}
public void setInformation(String text) {
if (mProgress != null) {
if (this.isHidden()) {
show(getActivity().getSupportFragmentManager());
}
mProgress.setText(text);
} else {
Bundle b = new Bundle();
b.putString(KEY, text);
setArguments(b);
}
}
public void hide(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction();
ft.hide(this);
ft.commit();
}
private void show(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction();
ft.show(this);
ft.commit();
}
}
The ProgressFragment is expected to attached(added) to the activity once, and there should be only one instance, then the client should only update its' information or hide it.
Usage in client(activity):
class MainActivity...{
ProgressFragment mFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFragment = ProgressFragment.newInstance(null);
FragmentTransaction fs = getSupportFragmentManager().beginTransaction();
fs.add(id, mFragment);
fs.commit();
}
//close the progress
mFragment.hide()
//show the progress
mFragment.setInformation("..")
}
However it does not worked as expected, sometime the progress view will show only at the first call or it does not even show.
Did I miss anything?
Don't set your onCreateView as #Nullable;
Use commitAllowingStateLoss();
Instead of just add(), use addToBackStack(). When you want to close it, just use the FragmentManager popBackStack():
getActivity().getSupportFragmentManager().popBackStack();
Related
I have created one dialog fragment in app. Following is the code for it.
public class AlertLoader extends DialogFragment {
Typeface fontRegular;
Bundle bundle;
String displayText = "";
public static AlertLoader newInstance(#NonNull String displayText) {
AlertLoader alertPopUpMenu = new AlertLoader();
Bundle args = new Bundle();
args.putString("displayText", displayText);
alertPopUpMenu.setArguments(args);
return alertPopUpMenu;
}
#Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null && dialog.getWindow() != null) {
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bundle = getArguments();
setStyle(STYLE_NO_TITLE, R.style.LoaderDialogTheme);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().setCanceledOnTouchOutside(false);
return inflater.inflate(R.layout.alert_dialog_loader, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
init(view);
}
private void init(View mainView) {
displayText = bundle.getString("displayText");
TextView mLoadingText = (TextView) mainView.findViewById(R.id.loadertext);
mLoadingText.setTextColor(Color.WHITE);
mLoadingText.setTypeface(fontRegular);
if (displayText == null || displayText.length() == 0) {
mLoadingText.setVisibility(View.GONE);
} else {
mLoadingText.setText(displayText);
mLoadingText.setVisibility(View.VISIBLE);
}
}
public void dismissCurrentView() {
getDialog().dismiss();
}
}
I am using following code to show dialog.
private void showLoader(String displayText) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
AlertLoader newFragment = AlertLoader.newInstance(displayText);
newFragment.show(ft, "dialog");
}
It is working fine. I am trying to dismiss it by following code.
private void dismissLoader() {
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
DialogFragment df = (DialogFragment) prev;
df.dismiss();
}
}
I am dismissing my loader before navigating to next activity. Following is my code where i am dismissing loader.
dismissLoader();
Intent intent = new Intent(getActivity(), ShareMediaActivity.class);
intent.putExtra(UserDefault.bundlePath, file.getAbsolutePath());
startActivity(intent);
But when i come back to previous activity , dialog still displays. This code for showing and dismissing is working fine in other cases.
I have tried several ways to dismiss it but not working. Anyone could help me with this?
Thanks.
Create a field for DialogFragment as below
private AlertLoader newFragment;
private void showLoader(String displayText) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
newFragment = AlertLoader.newInstance(displayText);
newFragment.show(ft, "dialog");
}
Then use that field to dismiss the DialogFragment
private void dismissLoader() {
if (newFragment != null) {
newFragment.dismiss();
}
}
how to Saving and Restoring Fragment state in Android ?
my code for save and restore state :
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("CurrentState",CurrentState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (savedInstanceState != null) {
// Restore last state for checked position.
CurrentState = savedInstanceState.getInt("CurrentState", 0);
}
.
.
.
switch (CurrentState){
case 1 :button_DisplayMemoris.performClick();break;
case 2 :
linearLayout_AddMemoris.setVisibility(View.VISIBLE);
linearLayout_Memoris.setVisibility(View.GONE);
linearLayout_DisplayMemoris.setVisibility(View.GONE);
break;
default:break;
}
return inflate;
}
when CurrentState=2 , linearLayout_AddMemoris Not displayed
How do I fix it?
update :
this is my activity :
public class ToolsActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tools);
displayView();
}
public void displayView() {
// update the main content by replacing fragments
Fragment fragment = = new MemoirsFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.frame_container, fragment);
ft.commit();
}
}
Is there a way to solve the problem?
I have no idea
Add in onCreate method null checking, now you are replace restored fragment by new fragment
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tools);
if (savedInstanceState == null)
displayView();
}
I'm getting this error while trying to launch a Fragment from a first Fragment :
java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.FragmentTransaction android.app.FragmentManager.beginTransaction()' on a null object reference
Here's the method where I'm getting the error :
#Override
public void onClick(View v) {
Fragment fragment = new PropertyFragment();
if (fragment != null) {
FragmentManager fragmentManager = fragment.getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
fragmentTransaction.replace(R.id.rent_viewer, fragment);
fragmentTransaction.addToBackStack(null);
// Commit the transaction
fragmentTransaction.commit();
}
}
Precisely, the following code instruction is causing the error :
fragmentManager.beginTransaction();
Here's how the class and the nested class look like :
public class RentFragment extends Fragment {
...
#SuppressWarnings("unused")
private OnRentFragmentInteractionListener mListener;
public RentFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnRentFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnRentFragmentInteractionListener");
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_rent, container, false);
myOnClickListener = new RentOnClickListener(getActivity());
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnRentFragmentInteractionListener {
public void onRentFragmentInteraction(Uri uri);
}
private static class RentOnClickListener implements View.OnClickListener {
private final Context context;
private RentOnClickListener(Context context) {
this.context = context;
}
#Override
public void onClick(View v) {
Fragment fragment = new PropertyFragment();
if (fragment != null) {
FragmentManager fragmentManager = fragment.getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
fragmentTransaction.replace(R.id.rent_viewer, fragment);
fragmentTransaction.addToBackStack(null);
// Commit the transaction
fragmentTransaction.commit();
}
}
}
}
FragmentManager will be null until it is attached to the activity.So use below code ,
If it is a nested Fragment use this.getChildFragmentManager() for your fragment class else use getActivity().getFragmentManager() or getActivity().getSupportFragmentManager().
Declare your FragmentTransaction and initialize it like this
FragmentTransaction fm;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
fm = getFragmentManager();
}
Then on your code, you can call this
Fragment fragment = new PropertyFragment();
FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.rent_viewer, fragment).addToBackStack(null).commit();;
Use the Customize Method in Base Class and use it.
public void replaceFragment(Fragment newFragment, Bundle bundle, boolean isAddToBackStack) {
String tag = newFragment.getClass().getSimpleName();
if (bundle != null) {
newFragment.setArguments(bundle);
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (getCurrentFragment() != null) {
ft.hide(getCurrentFragment());
}
ft.add(R.id.frameContainer, newFragment, tag);
newFragment.setRetainInstance(true);
if (isAddToBackStack) {
ft.addToBackStack(tag);
}
try {
ft.commitAllowingStateLoss();
} catch (Exception ex) {
ex.printStackTrace();
// ft.commitAllowingStateLoss();
}
}
You have to set context of activity as shown below on code HomeActivity.this.getSupportFragmentManager();
private Fragment fragment;
private FragmentManager fragmentManager;
fragmentManager=HomeActivity.this.getSupportFragmentManager();
transaction = fragmentManager.beginTransaction();
transaction.add(R.id.main_container, new ProfileFragment()).commit();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
fragmentTransaction.replace(R.id.rent_viewer, fragment);
fragmentTransaction.addToBackStack(null);
// Commit the transaction
fragmentTransaction.commit();
I'm having a problem with dynamic fragment . If I'm not change orientation , it work fine . When I change orientation , I click on ListView item . It's not change textview .
This is DynamicActivity class
public class DynamicActivity extends Activity implements FragmentCoordinator{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamic);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
ListContentFragment listContentFragment = new ListContentFragment();
DetailsContentFragment detailsContentFragment = new DetailsContentFragment();
transaction.add(R.id.listContainer, listContentFragment,"listContent");
transaction.add(R.id.detailsContainer, detailsContentFragment,"detailsContent");
transaction.commit();
}
#Override
public void onSetContentDetails(int index) {
FragmentManager fragmentManager = getFragmentManager();
DetailsContentFragment detailsContentFragment = (DetailsContentFragment)fragmentManager.findFragmentByTag("detailsContent");
detailsContentFragment.setContentDetails(index);
}
}
And DetailsContentFragment class
public class DetailsContentFragment extends Fragment {
TextView lbMess;
String[] array;
int saveIndex;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.details_content_fragment, container,false);
array = getResources().getStringArray(R.array.list_details);
lbMess = (TextView)v.findViewById(R.id.lbDetails);
int currentIndex = savedInstanceState == null ? 0 : savedInstanceState.getInt("indexContent",0);
setContentDetails(currentIndex);
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt("indexContent", saveIndex);
}
public void setContentDetails(int index) {
saveIndex = index;
lbMess.setText(array[saveIndex]);
}
}
I have debug but it doesn't have any error . Please give me some advice
I found the problems are :
When the system destroys and re-creates an activity because of a run-time configuration change, the activity automatically
re-instantiates existing fragments.
This isn’t a problem for “static” fragments declared in the activity’s layout.
But for “dynamic” fragments, i need to test for this situation to prevent creating a second instance of my fragment.
I check the Bundle argument passed to my activity’s onCreate() is null.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamic);
if(savedInstanceState == null)
{
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
ListContentFragment listContentFragment = new ListContentFragment();
DetailsContentFragment detailsContentFragment = new DetailsContentFragment();
transaction.add(R.id.listContainer, listContentFragment,"listContent");
transaction.add(R.id.detailsContainer, detailsContentFragment,"detailsContent");
transaction.commit();
}
}
And it work fine . I think is helpful for someone have same problems .
Yesterday I downloaded new HoloEverywhere library.
Currently, I have problem with tab navigation after screen rotation.
My Home Activity:
public class MainActivity extends Activity implements TabListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setUpTabs();
}
private void setUpTabs() {
String[] titles = {
"First", "Second",
};
ActionBar supportActionBar = getSupportActionBar();
for (int i = 0; i < titles.length; i++) {
ActionBar.Tab tab = supportActionBar.newTab();
tab.setText(titles[i]);
tab.setTag(MyFragment.TAG);
tab.setTabListener(this);
supportActionBar.addTab(tab, false);
}
supportActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
supportActionBar.setSelectedNavigationItem(0);
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction fragmentTransaction) {
final String fragmentTag = tab.getTag().toString();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (fragment == null) {
fragment = new MyFragment();
fragmentTransaction.add(android.R.id.content, fragment, fragmentTag);
} else {
fragmentTransaction.attach(fragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction fragmentTransaction) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag((String) tab.getTag());
if (fragment != null) {
fragmentTransaction.detach(fragment);
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction fragmentTransaction) {
}
}
And my Fragment class.
public class MyFragment extends Fragment {
public static final String TAG = MyFragment.class.getCanonicalName();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = new View(getActivity());
view.setBackgroundColor(Color.BLACK);
return view;
}
}
When I rotate the screen fragment not displaying. It displays when i select tab (which is not currently selected) manually.
I just solve the problem.
I post my code here and see if those can help you :D
if (savedInstanceState == null){
TabHomeFragment homeFragment = new TabHomeFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, homeFragment, "home_fragment").commit();
}else{
TabHomeFragment homeFragment = (TabHomeFragment) getSupportFragmentManager().findFragmentByTag("home_fragment");
}
Those code are located in OnCreate method.
When the Device rotate and Ortiention change, the fragment will recreate again. So add a if clase to check if there is already one here.
But I am using normal Fragment in Android. Hope it can help you a little.