access the content of EditText when back button is pressed - android

I'm working with fragments. Suppose I have fragmentA and fragmentB and I can go from fragmentA to fragmentB. In fragmentA I have a form (several edit texts). If I fill the form and then go to fragmentB and then press back button, all the information that I typed in the form is retained. From onCreateView I'm trying to do
String name = myEditText.getText().toString();
But I get empty result, even when I'm seeing the values in the form.
The question is, how can I access the content of this EditText in this situation?.
Solution
public void onResume() {
super.onResume();
String id = etIdHidden.getText().toString();
if(id.equals("")==false){
//Here do whatever you need, in my case I needed to change a bundle
mArgumentos=new Bundle();
mArgumentos.putString("id", ""+id);
}
};

Try fetching the value from the editText in the onResume() method. Also refer to the life-cycle of the fragment in the docs http://developer.android.com/guide/components/fragments.html

Related

Perform onClick on a view inside a fragment based on bundle param

Problem:
I need to perform onClick on a view present in Fragment depending upon the location from which the activity was launched.
I have setArguments on Bundle in myActivity's onCreate:
final String launchedFrom = getIntent().getStringExtra(LAUNCHED_FROM);
if (launchedFrom!=null) {
bundle.putBoolean("myStr", true);
}
Now, I fetch the argument from onCreateView of Fragment and perform click on 3rd item in the list:
if (this.getArguments().getBoolean("myStr")) {
mOptions.getAdapter().getView(3, null, null).callOnClick();
}
This opens the 3rd item on the list. Now, when I press back button the onCreateView is getting called again and the control is redirected to the 3rd item in the list as the bundle arguments have not changed on backPress.
I want to navigate back to the place from where the activity was called when I press the back button.
This is the code that is called when using .callonClick()
#Override
public void onViewSelected(List<Entry> faqs) {
Fragment fragment = FragmentB.newInstance(new ArrayList<>(faqs));
getFragmentManager().beginTransaction()
.replace(R.id.activity_frame_layout, fragment)
.addToBackStack(FragmentB.TAG)
.commit();
}
Solution#1: Not the best approach, if I move the code of onCreateView to onCreate, but I think there needs to be a better approach to solve this.

Android activity navigation save state

In the main activity ActivityA I replace FragmentA by fragment FragmentB. From FragmentB the user can start a new activity ActivityB. By hitting the back button in ActivityB, ActivityA is displayed showing FragmentA. I was expecting to see FragmentB with its last state. Do I have to save the state of the previous activities separately to provide this behaviour?
ActivityA(FragmentA) -> ActivityA(FragmentB) -> ActivityB
BACK
ActivityA(FragmentB)
In the main activity I set the current fragment using:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.a_main_frame_content, new FragmentB())
.addToBackStack(null)
.commit();
From the fragment I start a new activity using:
Intent intent = new Intent(getActivity(), ActivityB.class);
getActivity().startActivity(intent);
ActivityA is set as parent activity for ActivityB to provide proper navigation.
[UPDTATE] It looks like the problem lies in the different behaviour of navigating back and navigating up. If I navigate back, the activity is displayed in its last state while navigating up forces the activity to recreate.
Lets try this:
In the intent of the parentActivity(if you can set it before you create parentActivity its best, otherwise you may have to use setIntent):
currentActivityIntent.putExtra("random-unique-key-for-each-activity",
random-unique-key-for-each-activity);
And before you create a child activity, u put following in a map:
myKeyIntentMap.put(random-unique-key-for-each-activity, currentActivityIntent);
In the method triggered on "Up" event :
{
String parentKey = currentActivity.parentActivity.getIntent.getStringExtra("random-unique-key-for-each-activity");
Intent intentToLaunch = (Intent)myKeyIntentMap.get(parentKey);
intentToLaunch.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP );
startActivity(intentToLaunch);
}
This way, using the intent, even if your History Stack is A-someAct1-someAct2-B, and u launch intent resolving to A, it will be "brought to front" killing someActs.
P.S. I havent done any null checks and havent kept in mind the exact method names, just given you an approach.
Behaviour of "up" is sometimes misleading indeed. When I faced similar problem I preferred to save my time and not deal with saving states.
You can quickly solve it by catching your navigation "up" event in your Activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
}
return true;
}
This is happening because when you are moving to ActivityB activityA is going to puse and destroy state respectively, thus when you back to activity ActivityA ActivityA is starting again thus you are getting fragmentA as view. you need to save the state using sharedPfer. Use some flag to save the state in your onCreateView() check the state and set correct fragment for the view. Hope you have got my point.
public static final String PREFS_NAME = "mypref";
boolean isVisited;
//check sharedpref
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
isVisited= settings.getBoolean("isVisited", false);
if(!isVisited){
// set fragmentA
}else{
// set fragmentB
}
// inside fragment transaction block
Editor edit = settings.editor();
isVisited.setBoolean(true);
edit.commit();

fragment.getView() return null after backpressed

I try to change textview under attached fragment on activity so i stored attachedFragment as variable as code below
#Override
public void onAttachFragment(android.support.v4.app.Fragment fragment) {
super.onAttachFragment(fragment);
attachedFragment = fragment;
}
then when a button is clicked I call following code
if(attachedFragment != null && attachedFragment.getView() != null)
{
TextView tvGender = (TextView) attachedFragment.getView().findViewById(R.id.tv_gender);
if(tvGender!=null)
tvGender.setText(R.string.title_step_one_gender);
}
When I start the activity and it works fine until i changed into the next fragment and pressed back; the attachedFragment.getView() always returns null
My question:
How is it possible it returns null while the first time is okay?
What is the best solution to change textview/any other control
within fragment? There are lots of fragments and I only need to
change attached fragment.
nb: All code above are under main activity
Please correct me if I misunderstood your question. It sounds like your situation is, you attach fragment A, then you attach fragment B, then you press back, leaving you with fragment A. In this case, attachedFragment is just a variable, so it continues to point to B, but since B is now detached, it is null. Pressing back will not repopulate the variable attachedFragment with fragment A.
Try using findFragmentById or findFragmentByTag. Check out this thread for more info.

Bundle in a fragment created

Is there anyway to assign a Bundle to a fragment already created?. I tried something like this:
Bundle mArgumentos = new Bundle();
mArgumentos.putString("id", id);
this.setArguments(mArgumentos);
But I get the error: Fragment already active.
I'm just wondering if I can achieve this without overriding the onBackPressed() method.
My purpose with this is because I have a form for registry a new item. From here I can go to another fragment (lets call it fragment_B) with the new id of the item (I call fragment_B with a bundle assigning the new id). When the user presses back button, he gets to the previous form but the id is missing (this is because the form goes to the previous state, like empty), so if he tries to go to fragment_B again, he cant because the id.
Obviously the user cant go to fragment_B if the form has not been save. So the user saves the form and then press the button to go to fragment_B with its new id:
FragmentB fragment = new FragmentB();
Bundle mArgumentos = new Bundle();
mArgumentos.putString("id",id);
fragment.setArguments(mArgumentos);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(android.R.id.tabcontent, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
Any suggestions?.
Edit:
The fragments are not in the same activity. When I create a new item and press button save I should be in a "edit mode". This means that after I create the item I can come back and edit it. I'm just using the same fragment to edit and create. So, when I create the item, press the button to go to fragment_B and then press back button, I should be like "edit mode" of this item. This means that from fragment_B to the previous I should pass the id of the item created. That's why I wanna know if I can do this without overriding the onBackpress method.
Edit2:
If there is no other way to achieve this, I was thinking in override the onBackpress method like this:
//get the fragment where I'm staying on.
Fragment fragmentActual = this.getSupportFragmentManager().findFragmentById(android.R.id.tabcontent);
//get the tag of the fragment
String fragmentTag = fragmentActual.getTag().toString();
if (fragmentTag.equals("tagFragmentB")){
Fragment fragmentA = new FragmentA();
Bundle mArguments = fragmentActual.getArguments();
String id = mArguments.getString("id");
if(id != null){
fragmentA .setArguments(mArguments);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(android.R.id.tabcontent, fragment, "fragmentA");
ft.addToBackStack("fragmentA");
ft.commit();
}
}else{
super.onBackPressed();
}
This is working but as you have notice, this change the order of the fragments called by the user and this should be invisible for the user. So, this forces me to put more code in order to get the calls that the user did.
I'm kind of new with this, so maybe I have not the "Android thinking". If is there a better way to do what I want, I'm open to everything. I just want to do the thinks right and dont have problems in the future just because a user pressed a back button.
Well in my particular situation a made it work doing the following: I noticed that when I fill the form, saved it, then go to fragmentB and finally press back button, the information of my form was retained. So I put a hidden etidText in my form:
<EditText
android:id="#+id/textEditHiddenId"
android:visibility="gone"
android:inputType="number" />
When the button save is pressed, I set the content of this editText:
etIdHidden.setText(id);
When the activity is created, according to http://developer.android.com/guide/components/fragments.html, the method onResume is called after the onCreateView. So, I get the value of my textEditHiddenId in this method:
#Override
public void onResume() {
super.onResume();
String id= etIdHidden.getText().toString();
if(id.equals("")==false){
mArgumentos=new Bundle();
mArgumentos.putString("id", ""+id);
}
};
The first time, the content of textEditHiddenId is empty, but when backbutton is pressed and the onResume method is called, I get the content initialized and I can override my Bundle.
Simplest solution ever..

after configuration change fragment from backstack is now sharing the FrameLayout?

Problems with app:
When orientation changes the app is experiencing these problems:
Both FragmentA and FragmentC now occupy the FrameLayout container.
What works: Everything works as I want it to...prior to rotating the screen.
Activity description in brief:
EditActivity Purpose: edit collection and item fields.
Fragments this activity programmatically creates:
FragmentA - fragment for editing collection fields
FragmentB - ListFragment of items in collection
FragmentC - fragment for editing item fields.
Initial layout: FragmentA sits atop FragmentB, each in their own FrameLayouts.
When user clicks FragmentB's listview item: replace FragmentA with FragmentC to allow user to edit that item's fields. Now FragmentC sits atop FragmentB.
This seems like a very simple notion: the top portion of the activity is for editing either properties of the collection as a whole or a single item from the collection. I don't feel I have done anything wondrous with the layout so I'm a fair bit perplexed that a simple rotation of the phone (emulator) causes these problems that I am having such a dastardly time trying to fix.
Why the Android Fragment Guide example doesn't work for me: their example is much like what I am doing but their detail fragment is either being opened in a new activity or in its own Frame within the current activity, they don't do any swapping of fragments so I cannot glean how they would use the onSaveIstanceState to preserve the fragments that are visible and then use that information in onCreate to recreate the UI that was there prior to orientation change.
EDIT: took out one problem by caving and putting the listfragment in the XML, this solved the perpetual spinning "loading..." problem.
Solved. Oh, the rabbit holes I traveled... At any rate, if you run into problems like this a couple of things to consider:
ultimately I didn't have to write any code in onSaveInstanceState(Bundle outState).
Ultimately I didn't have to make any considerations about handling the backstack in onSaveInstanceState or deal with it the activity's onCreate.
When first "adding" fragments programmatically to the FrameLayout, use replace instead of `add' - this was likely one of the roots of my troubles.
in onCreate check if savedInstanceState's bundle is null, if(savedInstanceState == null), and if it is then I know that the activity hasn't been torn down previously by a configuration change, so here I build fragments that should be displayed right at activity start up. Other fragments that are programmatically brought to life elsewhere (ie, later than the activity's onCreate()), they don't belong in the if, they belong in the else:
else onSaveInstanceState != null and I know there's only one reason this thing's not null, because the system made a bundle named outState in onSaveInstanceState(Bundle outState) and hucked it at the activity's onCreate method where I can now get my grubbies on it. So it is here that I know a couple of things:
for sure the fragments I created in the activity's onCreate are still a part of the activity (I didn't detach or destroy them), but, I cannot make that same claim for the fragments brought to life via a user's actions, those fragments may or may not be currently (at the time of orientation aka configuration change) attached to the activity.
This is a good place for an if-this-thing-is-attached clause. One of things I initially messed up on was I failed to give ALL of my programmatically added fragments a tag; give all programmatically added fragments tags. I can then find out if the savedInstanceState bundle contains that key with savedInstanceState.containsKey(MY_FRAG_TAG) and with getFragmentManager().findFragmentByTag(MY_FRAG_TAG)
So here's the activity's onCreate (simplified):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
// ...omitted code...
if(savedInstanceState == null){
// create fragment for collection edit buttons
editCollection = FragmentA.newInstance(someVariable);
// programmatically add fragment to ViewGroup
getFragmentManager().beginTransaction().replace(R.id.edit_topFrame, editCollection, EDIT_COLLECTIONS_TAG).commit();
}
// else there be stuff inside the savedInstanceState bundle
else{
// fragments that will always be in the savedInstanceState bundle
editCollectionFragment = (FragmentA)getFragmentManager().findFragmentByTag(EDIT_COLLECTIONS_TAG);
// fragments that may not be in the bundle
if(savedInstanceState.containsKey(EDIT_ITEM_TAG)){
editItemFragment = (FragmentC)getFragmentManager().getFragment(savedInstanceState, EDIT_ITEM_TAG);
}
}
// This fragment is NOT programmatically added, ie, it is statically found in an XML file.
// Hence, the system will take care of preserving this fragment on configuration changes.
listFrag = (ListViewFragment)getFragmentManager().findFragmentById(R.id.ListFragment);
// create adapter
adapter = new EditCursorAdapter(this, null);
// set list fragment adapter
listFrag.setListAdapter(adapter);
// prepare the loader
getLoaderManager().initLoader(LOADER_ID, null, this);
}
And the Activity's listener for the list fragment, where FragmentC is swapped for FragmentA:
// listfragment listener
#Override
public void listFragListener(Cursor cursor) {
// checking backstack size
Log.d(TAG, SCOPE +"backstack size: "+getFragmentManager().getBackStackEntryCount());
// With each listview click there should be only one item in the backstack.
getFragmentManager().popBackStack();
// create new fragment
editItemFragment = FragmentC.newInstance(cursor);
// programmatically add new fragment
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.edit_topFrame, editItemFragment, EDIT_ITEM_TAG);
ft.addToBackStack("pop all of these"); // was testing different ways of popping
ft.commit();
// interesting: this reports the same value as the first log in this method.
// ...clearly addToBackStack(null).commit() doesn't populate the backstack immediately?
Log.d(TAG, SCOPE +"backstack size: "+getFragmentManager().getBackStackEntryCount());
}
And onSaveInstanceState is naked as a jay bird:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
Summary: I have the activity functioning exactly as I want it to.
Now, if I had a bunch of added fragments then I might handle them in a more programmatic fashion rather than by hard coding the if(savedInstanceState.contains(*hard coded key*). This I tested a little bit but cannot attest to its efficacy, however for someone out there this might spark an idea of what you can do:
Make a private Set of added fragments:
// Collection of Frag Tags
private Set<String> AddedFragmentTagsSet = new HashSet<String>();
In onAttachFragment do something like:
#Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
// logging which fragments get attached and when
Log.d(TAG, SCOPE +"attached fragment: " +fragment.toString());
// NOTE: XML frags have not frigg'n tags
// add attached fragment's tag to set of tags for attached fragments
AddedFragmentTagsSet.add(fragment.getTag());
// if a fragment has become detached remove its tag from the set
for(String tag : AddedFragmentTagsSet){
if(getFragmentManager().findFragmentByTag(tag).isDetached()){
AddedFragmentTagsSet.remove(tag);
}
Log.d(TAG, SCOPE +"contents of AddedFragmentTagsSet: " +tag);
}
}
Then in the activity's onCreate and within savedInstanceState clauses:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
// ...omitted code...
if(savedInstanceState == null){
// create fragment for collection edit buttons
editCollection = FragmentA.newInstance(someVariable);
// programmatically add fragment to ViewGroup
getFragmentManager().beginTransaction().replace(R.id.edit_topFrame, editCollection, EDIT_COLLECTIONS_TAG).commit();
}
// else there be stuff inside the savedInstanceState bundle
else{
// fragments that will always be in the savedInstanceState bundle
editCollectionFragment = (FragmentA)getFragmentManager().findFragmentByTag(EDIT_COLLECTIONS_TAG);
//////////// find entries that are common to AddedFragmentTagsSet & savedInstanceState's set of keys ///////////
Set<String> commonKeys = savedInstanceState.keySet();
commonKeys.retainAll(AddedFragmentTagsSet);
for(String key : commonKeys){
editItemFragment = FragmentC)getFragmentManager().getFragment(savedInstanceState, key);
}
}
}
...but that is untested and presented merely to spark ideas; in trying to figure out what was wrong with my activity's handling of configuration changes I did stumble and fumble in this direction and think it might bear fruit for the right person; though ultimately, obviously, I found a simpler way to fix my issues this time around.

Categories

Resources