Theoretically, lets say i have two classes with corresponding XML files - Activity and Frag
Activity.java
public class Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fragment fragment = new Frag();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragmentArea, fragment);
ft.commit();
}
}
Frag.java
public class Frag extends Fragment {
private TextView txtView;
public Frag() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_, container, false);
txtView = view.findViewById(R.id.textView);
return view;
}
public void setTextView(String str) {
txtView.setText(str);
}
}
activity xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.eksamen.chris.eksempelfragment.Activity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="#+id/fragmentArea">
</LinearLayout>
</android.support.constraint.ConstraintLayout>
Fragment xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.eksamen.chris.eksempelfragment.Frag">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment"
android:id="#+id/textView"/>
</FrameLayout>
As you can see, i have the method setTextView() in my Frag class. Obviously enough, what i would like to do is to call that method from my Activity class.
I have tried grasping this for some hours now, and i really cannot figure out a way to do this. Every example/tutorial out there makes my app crash.
Could someone explain to me how this works, taken the example we have in hand into consideration? Or maybe there is a better way to provide the fragment with data from my activity?
I'd be grateful!
Edit: awful indentation, had some issues, trying to fix.
In order to pass data from Activity to Fragment , you have to use :
Bundle
which is a KEY VALUE data structure for passing values between fragments and activity so at your onCreate() in Activity class will be
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String str = "your_string_here";
// 1 -
Bundle bundle = new Bundle();
// 2 -
bundle.putString("KEY", str);
Fragment fragment = new Frag();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
// 3 -
fragment.setArguments(bundle);
ft.replace(R.id.fragmentArea, fragment);
ft.commit(); }
and at your fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_, container, false);
txtView = view.findViewById(R.id.textView);
// 4 - NOTE : Should hould the same key at the Activity class :
String str = getArguments().getString("KEY");
setTextView(str);
return view;
}
Related
There is an activity containing a Button and a LinerLayout which is the container of Fragment. The layout of Fragment only contains a TextView. I want to send a string to fragment from activity, but what fragment received is null. Why?
xml of Activity:
<Button
android:id="#+id/load"
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="load" />
<!--the container of fragment-->
<LinearLayout
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" />
xml of Fragment:
<TextView
android:id="#+id/fragment_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Java code of Activity:
public class DynamicFragmentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamic_fragment);
findViewById(R.id.load).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//create fragment and set data
MyFragment myFragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("text", "demo");
myFragment.setArguments(bundle);
//commit
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, myFragment);
fragmentTransaction.commit();
}
});
}
}
Java code of Fragment:
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.myfragment, container, false);
TextView textView = (TextView) view.findViewById(R.id.fragment_text);
//receive data
String text = getArguments().getBundle("text")+"";
textView.setText(text);
return view;
}
}
Try this , Hope it helps ...........
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.myfragment, container, false);
TextView textView = (TextView) view.findViewById(R.id.fragment_text);
//change getBundle() to getString()
String text = getArguments().getString("text")+"";
textView.setText(text);
return view;
}
}
What you are doing now is get a Bundle called text and what you really want is get a string in the bundle:
Bundle arg = getArguments();
String txt = arg.getString("text");
I am sending data from one fragment to another, using interface. This works absolutely fine. Now I am trying to use onSaveInstanceState() to save the value in
a Fragment and retrieving in onCreate(). however i'm getting null in Bundle of onCreate(). P.S. everything works fine when i set the Fragment directly into the activity layout in xml. but when i set the fragment through java code into the activity, the onSaveInstanceState is failing. It is not saving the last known value. Please help. Pasting the code below. You can try it out to know the exact issue.
Fragment_A :
public class Fragment_A extends Fragment implements View.OnClickListener {
Button btnAdd;
int counter = 0;
Communicator comm;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null){
counter = savedInstanceState.getInt("counter", 0);
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
comm = (Communicator) getActivity();
btnAdd = (Button) getActivity().findViewById(R.id.btnAdd);
btnAdd.setOnClickListener(this);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("counter", counter);
}
#Override
public void onClick(View v) {
counter++;
comm.sendData(counter);
}
}
interface Communicator{
void sendData(int i);
}
=====
Activity :
public class Activity_InterComm extends Activity implements Communicator{
FragmentManager manager;
FragmentTransaction transaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intercomm);
Fragment_A fragment_1 = new Fragment_A();
Fragment_B fragment_2 = new Fragment_B();
manager = getFragmentManager();
transaction = manager.beginTransaction();
transaction.add(R.id.frag_a, fragment_1, "Frag1");
transaction.add(R.id.frag_b, fragment_2, "Frag2");
transaction.commit();
}
#Override
public void sendData(int i) {
manager = getFragmentManager();
Fragment_B fragment_b = (Fragment_B) manager.findFragmentById(R.id.frag_b);
fragment_b.setData("Button has been clicked " + i + " times");
}
}
=====
Fragment_B :
public class Fragment_B extends Fragment {
TextView txtMessage;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_b, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
txtMessage = (TextView) getActivity().findViewById(R.id.txtMessage);
}
public void setData(String message){
txtMessage.setText(message);
}
}
activity_intercomm.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--<fragment
android:id="#+id/frag_a"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:name="android.learning.com.fragintercomm.Fragment_A"/>
<fragment
android:id="#+id/frag_b"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:name="android.learning.com.fragintercomm.Fragment_B"/>-->
<LinearLayout
android:id="#+id/frag_a"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:background="#color/colorAccent"
android:orientation="vertical"/>
<LinearLayout
android:id="#+id/frag_b"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:background="#color/colorPrimaryDark"
android:orientation="vertical"/>
</LinearLayout>
the soluion I found was using getView() instead of getActivity() while initializing the button in Fragment_A. use btnAdd = (Button) getView().findViewById(R.id.btnAdd); instead of btnAdd = (Button) getActivity().findViewById(R.id.btnAdd);.
However, you can't use getView() in Fragment_B. The Textview freezes and, onSaveInstanceStat() doesn't work. Please suggest a solution.
The Android fragment lifecycle shows that when a fragment is added to the backstack and then removed/replaced, onDestroyView() is called, and later on, when the fragment returns to the layout from the backstack, onCreateView() is called.
From my understanding it means that the fragment's view is being destroyed and recreated. If the user has input text in an EditText in fragment A and goes to fragment B and then back to A, when the fragment comes back the EditText's contents will have been erased.
However, this is not happening in the following code; can anybody explain why? I have already verified that FragmentA's onDestroyView() is being called.
MainActivity.java
public class MainActivity extends FragmentActivity {
private Fragment currentFragment = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
addFragment(new FragmentA());
}
}
public void setCurrentFragment(Fragment fragment) {
this.currentFragment = fragment;
}
#Override
public void onBackPressed() {
if (currentFragment instanceof FragmentB) {
getSupportFragmentManager().popBackStackImmediate();
} else {
super.onBackPressed();
}
}
public void addFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment).addToBackStack(null).commit();
setCurrentFragment(fragment);
}
}
FragmentA.java
public class FragmentA extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
final EditText editText = (EditText)view.findViewById(R.id.editText);
Button button = (Button)view.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentB fragmentB = new FragmentB();
Bundle arguments = new Bundle();
arguments.putString("text", editText.getText().toString());
fragmentB.setArguments(arguments);
((MainActivity)getActivity()).addFragment(fragmentB);
}
});
return view;
}
#Override
public void onDestroyView() {
super.onDestroyView();
Log.d("Tag", "FragmentA.onDestroyView() has been called.");
}
}
FragmentB.java
public class FragmentB extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_b, container, false);
TextView textView = (TextView)view.findViewById(R.id.textView);
textView.setText(getArguments().getString("text"));
return view;
}
}
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.fragmenttest.MainActivity"
tools:ignore="MergeRootFrame" />
fragment_a.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
fragment_b.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Fragments in back stack retain their state in a Bundle. This includes the view hierarchy state with the current contents of EditTexts and such.
To destroy The Fragment .. Use This onDestroyView
or in onDetach
if (fragment != null) {
fragment = new YourFragment();
FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
ft.remove(fragment);
ft.commit();
}
i want add a fragment inside another one dynamically .
the outer fragment is a DialogFragment :
public class MapFragmentDialog extends DialogFragment implements OnMapClickListener, OnMapLongClickListener,
OnMarkerDragListener {
FragmentManager fmanager;
Fragment fragment;
SupportMapFragment supportmapfragment;
public static MapFragmentDialog newInstance() {
MapFragmentDialog f = new MapFragmentDialog();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.map_fragment, container, false);
// *********** add myMapFragment
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// add a fragment
MyMapFragment myFragment = new MyMapFragment();
fragmentTransaction.add(R.id.myfragment, myFragment);
fragmentTransaction.commit();
myMap = ((SupportMapFragment)getActivity().getSupportFragmentManager().findFragmentById(R.id.myMap)).getMap();
return v;
}
the map_fragment layout is like this :
<TextView
android:id="#+id/txtHelp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingBottom="6dip"
android:textAlignment="center"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="12sp" />
<FrameLayout
android:id="#+id/myfragment"
android:layout_width="0px"
android:layout_height="wrap_content" />
my inner fragment MyMapFragment :
public class MyMapFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.my_map_fragment, container, false);
return myFragmentView;
}}
the my_map_fragment layout contain :
<fragment
android:id="#+id/myMap"
android:layout_width="match_parent"
android:layout_height="300dp"
class="com.google.android.gms.maps.SupportMapFragment" />
i get an exception on getting the map fragment on my DialogFragment , a NullPointerException at this line
myMap = ((SupportMapFragment)getActivity().getSupportFragmentManager().findFragmentById(R.id.myMap)).getMap();
I remember seeing something about fragments in fragments working only dynamically and not by placing them XML. I think Abd El-Rahman El-Tama has the correct idea of using a frameLayout nstead of specifying a fragment directly
To change the Fragments dynamically all what you need is
1) A FrameLayout in your Layout as following:
<FrameLayout
android:id="#+id/fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
2) Initialize the FrameLayout into your activity as following:-
FrameLayout fragment = (FrameLayout) findViewById(R.id.fragment);
3) Start Fragment transaction as following:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new MyFragment()).commit();
Or
FragmentManager fragMan = new FragmentManager();
fragMan.beginTransaction ();
fragMan.replace (R.id.fragment);
fragMan.commit ();
I was able to create a tab layout using the tutorial in androidhive. I was wondering if I can put a side tab on it. . When you click an Item on the left side, an activity will be displayed on the right side.
I was wondering If I can do it. Thank you very much.
Try to design your layout as below:
Here its fragment_top_rated.xml file code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<LinearLayout
android:id="#+id/passenger"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="2dp"
android:orientation="horizontal"
android:weightSum="1">
<FrameLayout
android:id="#+id/frameLayout1"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight=".4"
android:background="#android:color/background_dark" >
</FrameLayout>
<FrameLayout
android:id="#+id/frameLayout2"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight=".6"
android:background="#android:color/darker_gray" >
</FrameLayout>
</LinearLayout>
</RelativeLayout>
You can load this screen on tabs click with the fragments into it.
EDITED:
Supposing that you have developed your project exactly same as the defined demo of you question link.
In your Tabactivity as you select places tab load the Fragment of places in the left side.
It defined in link on tab selected you just have to load fragments.
PlacesFragment
In your PlacesFragment write code as below:
public class PlacesFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_top_rated,
container, false);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft1 = fm.beginTransaction();
Fragment m_fragSet = new GamesFragment();
ft1.replace(R.id.frameLayout2, m_fragSet);
ft1.commit();
FragmentManager fmg = getFragmentManager();
FragmentTransaction ftrans = fmg.beginTransaction();
Fragment m_frag = new MoviesFragment();
ftrans.replace(R.id.frameLayout1, m_frag);
ftrans.commit();
return rootView;
}
}
Create right side fragment Games
public class GamesFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_games, container, false);
return rootView;
}
}
Here is MoviesFragment.java
public class MoviesFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_movies, container, false);
return rootView;
}
}
In your TabsAdapter define as below:
public class TabsPagerAdapter extends FragmentPagerAdapter {
FragmentActivity context;
public TabsPagerAdapter(FragmentManager fm,FragmentActivity act) {
super(fm);
context=act;
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
// Top Rated fragment activity
return new TopRatedFragment();
case 1:
// Games fragment activity
return new GamesFragment();
case 2:
// Movies fragment activity
return new MoviesFragment();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 3;
}
}
Here is the Output