I have an activity with a number of fragments. In all fragments, I get the views in onViewCreated, like this:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tv1 = (TextView)view.findViewById(R.id.tv1);
tv2 = (TextView)view.findViewById(R.id.tv2);
tv3 = (TextView)view.findViewById(R.id.tv3);
}
I'm not storing the textview's text in the state. One fragment extends ListFragment and I change the adapter's items and refresh the listview.
When I go back to previous fragments (I use popBackStack() because I need to use a Back button (app runs in kiosk mode), text in some fragments is lost while in others (and the listview) the changes done stay there.
I'm using replace to replace the current fragment in the frame.
EDIT
The values that are being lost are of TextViews and ImageButtons (image resource). The text in EditText views are not lost.
Why is this happening in just some fragments and how can I solve this data loss?
You have to use
android:freezesText="true"
In your layout textviews whose text you want to be preserved.
I hope it helps.
Let me see if I understand your situation:
You are showing an instance of Fragment1 which contains your TextView.
You replace your instance of Fragment1 on the screen with an instance of Fragment2.
You return to Fragment1, but when you do, the text in the TextView has been lost.
I have seen situations where this occurs because the instance of Fragment1 that contained the original TextView is not the same instance of Fragment1 that is shown the second time. If you are showing two different instances of Fragment1, the second instance will not display the text that the first instance contained in its own text view.
So take a look at the code that is managing your fragment transactions. Are you creating new instances of your fragments before showing them? If so, you'll have to keep references to the fragments that you want to retain instead of recreating them every time.
Another thing to look at would be how the TextView is being populated. Maybe the actual data is being lost somewhere.
Use Instance variables to store data inside each Fragment, if you are using replace E.g.:
String value = "";
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tv1 = (TextView)view.findViewById(R.id.tv1);
tv1.setText(value);
}
Note: Update value variable as well whenever textview data is being updated.
Related
My android application have BottomNavigationBar. It contains 5 fragments. One of its fragment contain nested fragment which is mutiple step process.
first nested fragment contain next button.Second nested fragment contain previous and next button.Third nested fragment contain previous and submit button. Each fragment have different EditText.
After adding the values in first fragment, when i click next button it goes to second fragment. In second fragment when i click previous button it goes to first fragment again and same process applies to second and third fragment
My questions is:
1)When previous button in second fragment is clicked, i want all the values of EditText in first fragment as it is and when again next button of first fragment is clicked, i want all the values of EditText in second fragment as it is. Is there any way to do this?
2)I want all the EditText values of all nested fragments when user clicked on submit button in third fragment.How to do that?
Yes,
This can be achieved using two ways,
1) Fragment savedInstanceState
https://stackoverflow.com/a/17135346/7316675
2) Keep you values stored at some activity or application level, and access it on resume of fragment screen
You could use a Bundle to store the values and then restore them when you restore the fragment. You could either do this in onStop() (recommended) or onPause().
Private static final String KEY_ADDRESS = "ADDRESS" ;
#Override
Public void onstop(){
Bundles state = new Bundle ();
String address = etv1.getText().toString();
// Get more strings from the etvs
state.putString(KEY_ADDRESS, address);
// Store more strings into the bundle
setInitialSavedState(state)
}
To restore the values you use either the saved instance state the system passed to onCreate() , or pass the bundle to a self created public bundle in onCreate() and access in onResume() like so:
String address = bundle.getString(KEY_ADDRESS);
As for the results being passed you could communicate the bundles to their parent activity whenever the next or previous button is pressed and do with it as you please when submit is pressed. Learn more on How to do that from the docs or this answer on how to do that
Solution of my first question.
I have used popBackStack() method of FragmentManager. Using this i can go back to the previous fragment of stack.I have added this code in OnClickListener of previous button
FragmentManager fm = getActivity().getSupportFragmentManager();
if(fm.getBackStackEntryCount()!=0){
fm.popBackStack();
}
Solution of my second question:
use method setArguments() to set the values and getArguments() to get the values
I have an Activity with several buttons and text elements. These elements reside in the Activity itself, not inside a fragment.
However, I want to be able to replace all this content with a PreferencesScreen fragment. Is this possible at all without putting the rest of the contents in my Activity that I want removed into a fragment and then call the .replace() function?
Currently I do
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new ProfileFragment())
.commit();
but this simply puts the ProfileFragment on top of my Activity. It overlays it. So I see and can interact with the ProfileFragment, but I also see the rest of the contents of the Acitvity underneath.
Again: I want to be able to replace all the content of my Activity with a PreferencesScreen fragment. Is this possible at all without putting the rest of the contents in my Activity that I want removed into a fragment and then call the .replace() function?
If you want to just hide the activity content, here's how you can set the background color of your Preference Fragment (tested with PreferenceFragmentCompat).
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setBackgroundColor(Color.WHITE);
}
Note that settings are typically opened in a new activity (as in Google apps).
If you're using PreferenceFragmentCompat, these SO answers may help you.
Styling issues: https://stackoverflow.com/a/32108439/2627680
Opening inner preference screens: https://stackoverflow.com/a/32540395/2627680
While developing my App i ran into some issues while "bugfixing"
In my onCreate() method of my MainActivity 1 service and 1 activity are being started.
They collect data (3 strings in the service, 1 string in the other activity) and i use the onAvitivityResult method to do the job. Because i use an activity instead of a single service it seems like a window is popping in and out quickly (Service and Activity both run AsyncTasks) and i dont really like that too much.
I have recoded basically everything to fit everything inside one service and pass the result on to another class that delivers the strings back to the MainActivity. I am using a default preset (swipeViews) and as it is right now the fragment only displays the string i assigned to it, well great, however that string is being updated by my service, yet the textView itself not.
How do i make my textView ("textView1") refresh and display the new string ("ClassC.datumh") without having to recreate the entire MainActivity?
This right here is only a snippet of the output method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
TextView textView1 = (TextView) rootView.findViewById(R.id.section_label);
textView1.setText(ClassC.datumh); //some random string that comes out of the service
rootView.invalidate();
return rootView;
}
earlier on i used to recreate the MainActivity simply, but as mentioned, i dont really like the "popping" effect created by this..
onCreateView is only called when the view is created. You don't want to recreate the TextView, just update its text.
make textView1 an instance variable in the MainActivity. When the MainActivity receives the string from the Service, have it run
textView1.setText(newStringReceivedFromYourService);
Reinitializing the entire ViewPager did the job. It recreated the TextViews just fine and i was able to see the new Values
ClassC.mViewPager.setAdapter(MainActivity.mMyFragmentPagerAdapter);
For this to work in my service that retrieved the Strings i had to make the ViewPager static in another class (ClassC) and thus i can access it at any given time.
this is bit when i'm creating view,
public static int a=0;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
a++;
View view = inflater.inflate(R.layout.fragment_layout, container, false);
editText = (EditText) view.findViewById(R.id.amount);
TextView tv = (TextView) view.findViewById(R.id.textView1);
Button button = (Button) view.findViewById(R.id.addTransaction);
button.setOnClickListener(this); ///fragments implements OnClickListener
editText.setText(""+a);
tv.setText(""+a);
return view;
}
when i load this fragment first time, my editText is empty, but when i load fragment again, value in the editText is same like in previous execution.
Is anyone has idea what i'm doing wrong? And how i can fix it?
** EDIT
i modified little bit my code, now each time when i'm loading fragment a is incremented. and io noticed weird behaviour. tv has has actual value of a, while editText still has old value
You need to move the settext ( and probably some other stuff) into a later method in the fragment life cycle e.g. onActivityCreated.
Before adding the fragment try to get the fragment by calling FindFragmentByTag("tag"), i think you are adding new fragments on top of each other. Also add your fragment transaction to back state and then to check if more than one fragments are added, press back button. I had similar problem, and the reason was i kept adding new fragments in activity
Fragments are tied to activities, so my guess is that the activity is not being destroyed, which means your fragment is not being destroyed and instead "resumed". Perhaps you want that code in the onResume callback? Take a look at the Fragment lifecycle: Android Fragments
Normally I would use a separate activity for each "screen" I wish to display, using different XML files.
However I'm working with Dynamically loading jar files into an android application, so therefore at runtime, I am not aware of how many activities there will be, or how many screens there will be.
At the moment, using java reflection, I am able to return a list of strings from the dynamically loaded java file, and draw each list item, as a separate button onto the screen. If one of these buttons is clicked, i want to be able to load a different "screen" on the stack. So when I press back from this new screen, it goes to the previous screen that called it.
Is it possible to do this without creating a new activity and passing a new intent to it and of course making relevant changes to the android manifest file?
To use blackberry functionality as an example - Is there an equivalent in android to blackberry's push and pop screens? Where the screen ur pushing/popping, would simply extent MainScreen?
If anyone has questions, or If I've been vague, please comment and I will try my best to explain myself, any help is very much appreciated.
The Android equivalent to BB's push/pop screen is startActivity()/finish(). However, you can manage your own views in a single activity by either using a container view (such as ViewSwitcher, as #hasanghaforian suggests) or by simply calling setContentView() with a new view hierarchy whenever you want to change the screen. Be aware that when you call setContentView, any view references that you obtained by calling findViewById will be stale.
In my opinion you should use Fragment. I assume that you have some piece of code where you iterate over the strings:
for(String def : definitions) {
Fragment f = new CustomFragment();
Bundle b = new Bundle();
b.putString("STRING_DEF",def);
f.setArguments(b);
fragments.add(f);
}
in above piece of code a collection of Framents is just created. Let's look at the CustomFragment implementation:
CustomFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String def = getArguments.getString("STRING_DEF");
//write code to create view
return view;
}
}
Now in your ListActivity you have to implement on click listener more or less like this like this
public void onListItemClick(ListView l, View v, int position, long id) {
FragmentManager fragMgr = getFragmentManager();
FragmentTransaction t = fragMgr.beginTransaction();
t.replace(R.id.id_of_view_place_holder_for_fragment,
fragments.get(position),"FRAGMENT_TAG");
t.commit();
}
you can use ViewSwitcher. ViewSwitcher is a ViewAnimator that switches between two views, and has a factory from which these views are created. You can either use the factory to create the views, or add them yourself. A ViewSwitcher can only have two child views, of which only one is shown at a time.Or you can use fragments.
If you refer to if it is possible to have different layouts in the same activity, the answer is yes.
Activities are independent of layouts, you don't assign the layout for an activity in the manifest, you define what layout to use in the activity calling setContentView() method from Activity class to set a layout.
So if you want to have some layouts (screens) the only thing you have to do is define various layouts and use them when you want calling setContentView(R.layout.the layout), after this call, the layout chosen will be displayed.
If you can't create the layout statically by xml, you can create it dinamically by code as needed by demand each time you want.
In addition you can have a stack of layouts, each time you need a new screen, build it, push it to the stack and call setContentView() method, when you don't need it more, pop off the stack and call setContentView() with the new layout in the top of the stack.
Hope it help you