Button's onClick method modifying a global variable in Fragment - android

The code in my fragment is structured as follows:
public class FragmentScanQR extends Fragment {
...
private Button qrFromCameraBtn;
private View rootView;
...
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.qrsource, container, false);
qrFromCameraBtn = (Button)rootView.findViewById(R.id.qrViaCameraBtn);
qrFromCameraBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rootView = inflater.inflate(R.layout.fragmenttab1, container, false);
}
});
return rootView;
}
The onCreateView method of fragment returns a value of type android.view.View. The qrFromCameraBtn button's onClick method modifies the same View variable. In the output, when I click on the botton, the layout doesn't change to R.layout.fragmenttab1 (which I wish to achieve) but remains the same. How can I do this?

If I understand what you need, you want to replace your first fragment with a new one. You can do that like so:
//Where Article fragment is your new fragment.
ArticleFragment newFragment = new ArticleFragment();
FragmentTransaction transaction = getSupportFragmentManager().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
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Source: https://developer.android.com/training/basics/fragments/fragment-ui.html

If you want to just replace the layout,this link might help you.
Android - How to dynamically change fragment layout.
Just add the following code on button click method
qrFromCameraBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RelativeLayout rl = (RelativeLayout) findViewById(R.id.about);
rl.removeAllViews();
rl.addView(View.inflate(myView.getContext(), R.layout.about, null));
}
});

Related

Fragment is recreate on back press from other Fragment

I am facing a problem in regarding fragment.
In my scenario,
There are two fragment associated with FragmentActivity.
In FragmentActivity, there are a container layout (Frame Layout) in which all fragment will replace.
public void replaceFragment(Fragment fragmentClass) {
String selectedFragment = fragmentClass.getClass().getName();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction
.replace(R.id.content_frame, fragmentClass);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
First time , I set a List type fragment (Fragment A) in which get the data from web service and papulate over listview. I execute the AsyncTask from onCreateView() method.
In MainActivity: onCreate
SherlockFragment fragment = new FragmentA();
replaceFragment(fragment);
On list item click of Fragment A, Fragment A will callback the activity method to replace it to details type fragment Fragment B.
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
callback = (ICallBack) activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
/*View rootView = inflater.inflate(R.layout.fragment_locate, container,
false);*/
View rootView = inflater.inflate(R.layout.fragment_a, container,
false);
ListView list = (ListView) rootView
.findViewById(R.id.listView);
adapter = new MyListAdapter();
list.setAdapter(adapter);
list
.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent,
View convertView, int position, long id) {
SherlockFragment fragment = new SalonDetailFragment();
callback.replaceFragment(fragment);
}
});
ListDataTask task = new ListDataTask();
task.execute();
return rootView;
}
class ListDataTask extends AsynTask<Void,Void,List<Data>>{
public Void doInBackground(Void parems){
List<Data> = getDataFromServer();
}
onPostExecute(List<Data> data){
adapter.addAllData(data);
adapter.notifyDataSetChanged();
}
}
When I press back button, from Fragment B then Application will show Fragment A but it execute Asynctask again and get the data to papulate the listview.
So I need to know, How to maintain the pervious state of Fragment like Activity.
Is there are any way to not to create Fragment after come back from Other activity
Have a look my pseudo code.
I got solution. Simple.... do the check null value of rootview
public class FragmentA extends Fragment {
View _rootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (_rootView == null) {
// Inflate the layout for this fragment
_rootView = inflater.inflate(R.layout.fragment_a, container, false);
// Find and setup subviews
_listView = (ListView)_rootView.findViewById(R.id.listView);
...
} else {
// Do not inflate the layout again.
// The returned View of onCreateView will be added into the fragment.
// However it is not allowed to be added twice even if the parent is same.
// So we must remove _rootView from the existing parent view group
// (it will be added back).
((ViewGroup)_rootView.getParent()).removeView(_rootView);
}
return _rootView
I have the same problem and solved by replacing
fragmentTransaction
.replace(R.id.content_frame, fragmentClass);
to
fragmentTransaction
.add(R.id.content_frame, fragmentClass);
Replace will always create new instance on back press while Add is just add a new fragment in Stack. for more information check this link

nullpointer running method of fragment from activity when using views

My Fragment
public class CustomFrag extends Fragment {
private Button btn;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.button_fragment, container, false);
btn = (Button)view.findViewById(R.id.button1);
return view;
}
public void sendItem(String item) {
btn.setText(item);
}
}
And in my activity
public void loadFragment(String data) {
// Load up new fragment
Fragment fragment = new CustomFrag();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.contentFragment, fragment, "custFrag");
transaction.addToBackStack("custFrag");
transaction.commit();
// Required before calling fragment methods
getSupportFragmentManager().executePendingTransactions();
// Load fragment with data
CustomFrag frag = (CustomFrag) getSupportFragmentManager().findFragmentByTag("custFrag");
frag.sendItem(data);
}
I'm getting a nullpointer exception any time I attempt to use the views of my fragment. If I try to load the view inside the method as well, it will not work
i.e. inside sendItem()
btn = (Button)getView().findViewById(R.id.button1);
My layout (button_fragment) contains the button:
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Because you have executed the transaction does not mean that the fragment has actually created its view. Which is why btn is still null.
To pass data from the activity to the fragment, use the argument bundle:
Fragment fragment = new CustomFrag();
Bundle args = new Bundle();
args.putString("item", data);
fragment.setArguments(args);
Then, in onCreateView:
btn = (Button)view.findViewById(R.id.button1);
btn.setText(getArguments().getString("item"));
See this Best practice for instantiating a new Android Fragment question and the first answer.
The problem here is that the fragment's layout is not drawn yet when sendItem(...) is called. Which means btn is null at that point. Instead, this is how you're supposed to do it (see http://developer.android.com/guide/components/fragments.html):
public class CustomFrag extends Fragment {
private Button btn;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.button_fragment, container, false);
btn = (Button)view.findViewById(R.id.button1);
btn.setText(getArguments.getString("item"));
return view;
}
}
And
public void loadFragment(String data) {
// Load up new fragment
Fragment fragment = new CustomFrag();
Bundle args = new Bundle();
args.putString("item", data);
fragment.setArguments(args);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.contentFragment, fragment, "custFrag");
transaction.addToBackStack("custFrag");
transaction.commit();
// Required before calling fragment methods
getSupportFragmentManager().executePendingTransactions();
}
Edit:
njzk2 was faster, but I hope the details I gave will help you further. In any case, the link he gave explains nicely why you should do it like that.

Android fragment popBackStack and replace not removing view

I'm trying to learn to use fragments.
Suppose i have one activity, with 2 fragments - FragmentA and FragmentB.
In my activity i add the fragment, with what i thought was the ability to remove a fragment view when i press the back button:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
mFragmentA = new FragmentA();
fragmentTransaction.add(R.id.fragment_container, mFragmentA).addToBackStack("fragA").commit();
}
and in my FragmentA's view, i have 2 buttons. one supposedly for going back, and one for replacing FragmentA with FragmentB.
So here's what FragmentA looks like:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a_layout, null);
Button backButton = (Button) view.findViewById(R.id.frag_a_back);
backButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
getFragmentManager().popBackStack("fragA", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
});
Button nextButton = (Button) view.findViewById(R.id.frag_a_next);
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
FragmentB fragB = new FragmentB();
ft.replace(R.id.fragment_container, fragB).commit();
}
});
container.addView(view);
return super.onCreateView(inflater, container, savedInstanceState);
}
Question:
When i go to fragmentB or if i press the back button, why does FragmentA's two buttons still show up on the screen? I want the back button to remove FragmentA. Is the fragment getting removed/detached but the view is not?
(i'm using FrameLayout for everything and i can see FragmentA view still there)
EDIT =============================
okay i realized there is a onDestroyView() method, but i'm not sure if it's the right way to remove my FragmentA's views?
it would require me to hold on to an instance of the parent view, and a reference var to my fragment layout view; and that way i can use the parent view to remove all views here
You don't need to do container.addView(view); explicitly. Just return the inflated View. The following changes might help.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_a_layout, null);
Button backButton = (Button) view.findViewById(R.id.frag_a_back);
backButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
getFragmentManager().popBackStack("fragA", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
});
Button nextButton = (Button) view.findViewById(R.id.frag_a_next);
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
FragmentB fragB = new FragmentB();
ft.replace(R.id.fragment_container, fragB).commit();
}
});
//container.addView(view);
return view;
}

Fragments the right way

I'm trying out some fragments right now. I've got a fragment with a button and when I click that button I switch to another fragment. Now when I push on the back button I return to the first fragment that's good. Now when I click again on that button a new fragment is started. So I always start a new fragment. I think thats not the way it needs to be done. Is there a better way to for example resume the already created fragment?
My code:
public static class PlaceholderFragment extends Fragment{
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
Button test = (Button)rootView.findViewById(R.id.button);
test.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View view)
{
Log.d("Test", "Button clicked.");
TestFrag newFragment = new TestFrag();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
return rootView;
}
}
public static class TestFrag extends Fragment {
public TestFrag() {
Log.d("Test","New fragment");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main2, container, false);
return rootView;
}
}
When you use the fragment transaction you can specify a tag for the fragment
fragmentTransaction.add(R.id.main_fragment, newFragment, fragTag);
fragmentTransaction.commit();
Then later you can find a fragment by tag from the fragmentManager
newFragment = fragMan.findFragmentByTag(fragTag);
if newFragment then is null you should create the Fragment since it wasnt found by the tag
Thanks to Joakim:
fragmentTransaction.add(R.id.main_fragment, newFragment, fragTag); fragmentTransaction.commit();
Then later you can find a fragment by tag from the fragmentManager
newFragment = fragMan.findFragmentByTag(fragTag); if newFragment then is null you should create the Fragment since it wasnt found by the tag. If the tag isn't null you can just add and commit the new one.

change Fragment View

I have an app with fragments. It works fine.
One of the fragments has a button, and when pressed I want to change the view.
public class BikeRecap extends Fragment {
public static Activity activity;
public static Context context;
/** Called when the activity is first created. */
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
activity = getActivity();
context = activity.getApplicationContext();
View view = inflater.inflate(R.layout.bike_recap, container, false);
ImageButton details = (ImageButton) item.findViewById(R.id.details);
details.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
OpenNewView();
}
});
return view;
}
OpenNewView() should change the view, so, the user is in the same tab, but the content is different
Is it possible?
You can't have a fragment inside a fragment.
Try this code:
FragmentManager fragmentManager2 = getFragmentManager();
FragmentTransaction fragmentTransaction2 = fragmentManager2.beginTransaction();
DetailFragment fragment2 = new DetailFragment();
fragmentTransaction2.addToBackStack("abc");
fragmentTransaction2.hide(BikeRecap.this);
fragmentTransaction2.add(android.R.id.content, fragment2);
fragmentTransaction2.commit();
I think you can, pretty easily, do what you are trying to do. If OpenNewView is implemented by the Activity, instead of by the fragment:
getActivity().openNewView(...)
... then the Activity can easily replace the current fragment with a new one, using the standard transaction mechanism.
G. Blake Meike
Marakana
Programming Android 2ed is now in stores:
http://bit.ly/programmingandroid

Categories

Resources