I have a function1 in FragA, and a function2 in FragB
What I want is : when FragA use function1, it should notify FragB to use functionB
So what is the easiest and good way to do it ?
Thanks
1. Using an EventBus
Use an EventBus to send event to the other fragment. You can try Otto or EventBus
2. Using FragmentManager and public method (I don't like these)
As #Alexander suggested, you can get reference to the other fragment and call its method
3. Using Broadcasts
You can use a LocalBroadcast and attach a receiver in both fragments to call the method when they receive a broadcast.
following is the example for your question, well it's quite crude in code but will give you an idea about how you can implement your requirement.
your activity should look like this FragmentTestOneActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import test.spinner.one.FragmentA;
import test.spinner.one.FragmentB;
public class FragmentTestOneActivity extends AppCompatActivity implements FragmentA.MyEventMaker{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_test_one);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
#Override
public void sendData(String text) {
Log.d("FragmentTestOneActivity", "Text: "+text);
FragmentB.setData(text);
}
}
and below is the layout for the above activity activity_fragment_test_one.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:background="#cf5f5b"
android:orientation="horizontal"
android:padding="10dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="some.fragment.one.FragmentTestOneActivity"
tools:showIn="#layout/activity_fragment_test_one">
<fragment
android:id="#+id/fragment_one"
android:name="test.spinner.one.FragmentA"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:layout_weight="0.5"
tools:layout="#layout/fragment_" />
<fragment
android:id="#+id/fragment_two"
android:name="test.spinner.one.FragmentB"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:layout_weight="0.5"
tools:layout="#layout/fragment_b" />
</LinearLayout>
FragmentA.java
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
/**
* A simple {#link Fragment} subclass.
*/
public class FragmentA extends Fragment {
private MyEventMaker myEventMaker;
private Button button;
public FragmentA() {
// Required empty public constructor
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
myEventMaker = (MyEventMaker)context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_, container, false);
button = (Button) view.findViewById(R.id.FragmentA_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myEventMaker.sendData("something");
}
});
return view;
}
public interface MyEventMaker{
void sendData(String text);
}
}
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:gravity="center"
android:background="#b1a2f3"
tools:context="test.spinner.one.FragmentA">
<Button
android:id="#+id/FragmentA_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button" />
</LinearLayout>
FragmentB
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* A simple {#link Fragment} subclass.
*/
public class FragmentB extends Fragment {
private static TextView textView;
public FragmentB() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view =inflater.inflate(R.layout.fragment_b, container, false);
textView = (TextView)view.findViewById(R.id.FragmentB_textView);
return view;
}
public static void setData(String text){
Log.d("FragmentB","Text: "+ text);
textView.setText(""+text);
}
}
fragment_b.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:background="#efabca"
android:gravity="center"
tools:context="test.spinner.one.FragmentB">
<TextView
android:id="#+id/FragmentB_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
</LinearLayout>
From func1 find your B fragment using FragmentManager.findFragmentByTag (or byId) then call your function on that fragment.
Or you can use a 3rd party even bus such as Otto
Related
I'm trying to learn android and am having an issue with this project. I have set up a fragment tab host with four fragments. What I would like to do is have the first three fragments be interactive with the user and when they tab over to the 4th tab, it will display all the information they put in on the first three. I figured I can pass the info overriding on onPause() as the trigger as I don't want to use a button press. Right now, I'm just trying to get the EditText to work to make sure I'm doing everything right. I'm not sure if I'm using the fragment transaction correctly, or the way I'm trying to collect the edit text field. Later on I hope to pass the information via a bundle. Any help would be appreciated.
Main:
package valdes.fragmenttabsmenu;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
import android.app.FragmentTransaction;
public class MainActivity extends FragmentActivity implements WelcomeFragment.WelcomeListener {
private FragmentTabHost mTabHost;
private String firstName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
mTabHost.addTab(mTabHost.newTabSpec("Home").setIndicator("Home", null), WelcomeFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Demographics").setIndicator("Demographics", null), DemographicsFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Questions").setIndicator("Questions", null), QuestionsFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Overview").setIndicator("Overview", null), OverviewFragment.class, null);
}
#Override
public void getFristName(String first_Name){
firstName = first_Name;
OverviewFragment fragment = new OverviewFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
fragment.setFirstName(firstName);
ft.addToBackStack(null);
ft.commit();
}
}
Fragment 1 - getting info
package valdes.fragmenttabsmenu;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
public class WelcomeFragment extends Fragment {
public WelcomeFragment() {
// Required empty public constructor
}
interface WelcomeListener{
public void getFristName(String firstName);
}
private WelcomeListener listener;
private String firstName;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_welcome, container, false);
EditText editText = (EditText) view.findViewById(R.id.first_name);
firstName = editText.getText().toString();
return view;
}
#Override
public void onAttach(Context context){
super.onAttach(context);
this.listener = (WelcomeListener)context;
}
#Override
public void onPause(){
super.onPause();
if(listener != null){
listener.getFristName(firstName);
}
}
}
Fragment 1 XML
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="#dimen/activity_horizontal_margin">
<TextView
android:id="#+id/welcome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:textSize="25sp"
android:text="#string/welcome_message"/>
<EditText
android:id="#+id/first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/first_name"/>
<EditText
android:id="#+id/last_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/last_name"/>
<Spinner
android:id="#+id/birthday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="#array/months"/>
</LinearLayout>
Fragment 2 - getting info
package valdes.fragmenttabsmenu;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class OverviewFragment extends Fragment {
private String firstName;
private String lastName;
public OverviewFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_overview, container, false);
}
#Override
public void onStart(){
super.onStart();
View view = getView();
if(view != null){
TextView name = (TextView) view.findViewById(R.id.OV_name);
name.setText(firstName);
}
}
public void setFirstName(String firstName){this.firstName = firstName;}
}
Fragment 2 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"
tools:context="valdes.fragmenttabsmenu.OverviewFragment">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:textSize="25sp"
android:layout_weight="1"
android:text="#string/overview"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
android:textSize="40sp"
android:text="Responses go here"/>
<TextView
android:id="#+id/OV_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="TEST"/>
<Button
android:id="#+id/submit_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/submit"/>
</LinearLayout>
Create a Listner for get/set data between fragments and implement it on activity like this
InteractionLister.java
public interface InteractionLister {
void setData(String data);
String getData();
}
MainActivity.java
public class TabActivity extends Activity implements InteractionLister{
private String mData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void setData(String data) {
this.mData = data;
}
#Override
public String getData() {
return mData;
}
}
TabFragment1.java
public class TabFragment1 extends Fragment {
InteractionLister interactionLister;
private static final String TAG = TabFragment1.class.getSimpleName();
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Log.w(TAG,"Data from other fragment " + interactionLister.getData());
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
interactionLister = (InteractionLister) activity;
}
}
I have a fragment(A) , where another fragment(B) is being opened . When I press back button it just refreshes the fragment(B) instead of exiting from it and returning to fragment A.
I tried poping back the fragment A in the Activity's onBackPressed callback method but it didn't change a thing :
#Override
public void onBackPressed() {
if(B.active)
{
mFragmentManager.popBackStack( A.TAG , 0);
B.active = false;
}
}
** the active boolean is just something I added as part of the solution. It's initialized to TRUE once the fragment is instantiated.
I don't know how to commit a project!
package com.example.a;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* Created by 77930 on 2015/11/9.
*/
public class ActivityA extends AppCompatActivity{
#InjectView(R.id.c)
LinearLayout c;
#InjectView(R.id.btn)
TextView btn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.c);
ButterKnife.inject(ActivityA.this);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.e, FragA.newInstance(), "A");
// fragmentTransaction.addToBackStack("A");
fragmentTransaction.commitAllowingStateLoss();
}
});
}
}
package com.example.a;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* Created by 77930 on 2015/11/10.
*/
public class FragA extends Fragment{
private View rootView;
public static FragA newInstance() {
return new FragA();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public FragA() {
}
#InjectView(R.id.a)
LinearLayout a;
#InjectView(R.id.btn)
TextView btn;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fraga,container,false);
ButterKnife.inject(this,rootView);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.e, FragB.newInstance(), "B");
fragmentTransaction.addToBackStack("B");
fragmentTransaction.commitAllowingStateLoss();
}
});
return rootView;
}
}
package com.example.a;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* Created by 77930 on 2015/11/10.
*/
public class FragB extends Fragment{
private View rootView;
public static FragB newInstance() {
return new FragB();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public FragB() {
}
#InjectView(R.id.b)
LinearLayout b;
#InjectView(R.id.btn)
TextView btn;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragb,container,false);
ButterKnife.inject(this, rootView);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().getSupportFragmentManager().popBackStackImmediate();
}
});
return rootView;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:id="#+id/c"
android:background="#4b14b1"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/e"
android:layout_width="match_parent"
android:layout_height="300dp">
</FrameLayout>
<TextView
android:id="#+id/btn"
android:textColor="#ffffff"
android:textSize="100dp"
android:gravity="center"
android:text="c"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:id="#+id/a"
android:background="#4b14b1"
android:layout_height="match_parent">
<TextView
android:id="#+id/btn"
android:textColor="#ffffff"
android:textSize="100dp"
android:gravity="center"
android:text="A"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:id="#+id/b"
android:background="#4b14b1"
android:layout_height="match_parent">
<TextView
android:id="#+id/btn"
android:textColor="#ffffff"
android:textSize="100dp"
android:gravity="center"
android:text="B"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
A repo with example: https://bitbucket.org/troffel/drawer-button-error
I've come across an issue I can't for the life of me figure out. From a much larger project I was able to deduce it into a smaller dummy project.
Problem:
When the app launches, the buttons in the drawer menu works correctly. However, after changing orientation one or more times the buttons all of a sudden require two key presses.
When logging out events, it shows that the eventlistener connected to the clicked views is triggered, however nothing seem to happen on first click.
I added the main files to the post, repo so you can replicate it if interested.
Any help is much appreciated.
Main layout:
</LinearLayout>
<LinearLayout
android:id="#+id/left_drawer"
android:orientation="vertical"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/background_light">
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
layout of initial fragment(category_fragment):
<ListView
android:id="#+id/left_drawer_listview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:choiceMode="singleChoice"/>
<View
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="#ecebec"/>
<TextView
android:id="#+id/drawer_settings"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textColor="#android:color/black"
android:textSize="20sp"
android:clickable="true"
android:onClick="openSettings"
android:gravity="center_vertical"
android:text="Settings"
android:paddingLeft="10sp"/>
</LinearLayout>
fragment that replaces the initial(preffragment):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/settings_checkbox_container"
android:layout_weight="1">
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="#+id/settings_back"
android:text="Save"
android:layout_weight="1"/>
</LinearLayout>
Mainactivity:
package com.example.testdrawer;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.left_drawer, new CategoryFragment());
fragmentTransaction.commit();
}
public void openSettings(View v){
FragmentManager fmanager = getSupportFragmentManager();
FragmentTransaction ftrans = fmanager.beginTransaction();
PrefFragment prefFragment = new PrefFragment();
ftrans.replace(R.id.left_drawer, prefFragment);
ftrans.commit();
Log.i("test", "Opening settings");
}
}
categoryfragment code:
package com.example.testdrawer;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class CategoryFragment extends Fragment{
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View v = inflater.inflate(R.layout.category_fragment, container, false);
//drawer menu
return v;
}
}
Preffragment.java:
package com.example.testdrawer;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class PrefFragment extends Fragment{
private Context context;
private View checkbox_container;
private Button settingsBack;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getActivity().getApplicationContext();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.preffragment, container, false);
checkbox_container = v;
settingsBack = (Button) v.findViewById(R.id.settings_back);
settingsBack.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
saveSettings();
}
});
//setupSimplePreferencesScreen();
return v;
}
public void saveSettings(){
//setSettings(checkbox_container);
FragmentManager fmanager = getFragmentManager();
FragmentTransaction ftrans = fmanager.beginTransaction();
ftrans.replace(R.id.left_drawer, new CategoryFragment());
ftrans.commit();
Log.i("test", "saving settings");
}
}
OK! This is super weird, but I found the problem.
Using replace(container, fragment) instead of add(container, fragment) in my solved the issue.
The problem was that I was calling add(container, fragment) in my activitys onCreate method. This meant that when an orientation change happened, it would call add(container, fragment) on top of the already existing one.
replace(container, fragment) works because it, logically, replaces the existing one.
A solution that includes using add(container, fragment) would be to have remove(fragment) in my activitys onDestroy method, thus avoiding doable drawing.
Hope it saves someone else some time!
I have a fragment with the following layout: my_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/appName"
android:id="#+id/textView" android:layout_gravity="center"
android:layout_margin="5dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/button1"
android:id="#+id/button1"
android:layout_gravity="center"/>
and corresponding MyFragment.java
package com.example.appdemo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.top_bar, container, false);
Button button1 = (Button)view.findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(getActivity(), "Button Pressed", Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
and this is hosted inside MainActivity.java
package com.example.appdemo;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
with the following layout activity_main.xml
<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" >
<fragment
android:id="#+id/fragment"
android:name="com.example.appdemo.MyFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
Now, my question is why does this only work when I extend FragmentActivity? I'd like to extend Activity. How do I accomplish that?
Why does this only work inside a host class that extends FragmentActivity?
Because you are inheriting from android.support.v4.app.Fragment instead of android.app.Fragment.
I have an activity which displays two fragments:
When activity is created, it displays Fragment1.
When the user presses the button on Fragment1, it displays Fragment2, adding to backstack.
Fragments are straightforward. Fragment1 contains CheckBox and EditText. Fragment2 contains simple TextView. Also I call setRetainInstance(true) in fragment's onCreate(...) method.
Problem: Fragment1 loses its state if Fragment2 is displayed and device is rotated twice. However, everything works as expected if device is rotate only once.
Steps to reproduce:
Launch application.
Check CheckBox and type some text into EditText
Press Button to launch Fragment2
Rotate device
Rotate device once again
Press Back button on your device (or ESC on Emulator) to return back to Fragment1
Fragment1 lost its state (checkbox is unchecked and EditText is empty).
However, if you return back to Fragment1 after step#4 - Fragment1 keeps its state as expected.
Where is the problem? All code is below, including layouts.
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
fragment1.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" >
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox" />
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</EditText>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Fragment2" />
</LinearLayout>
fragment2.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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment #2" />
</LinearLayout>
FragmentTestActivity.java:
package fragmenttest.example.com;
import android.app.Activity;
import android.app.FragmentManager;
import android.os.Bundle;
public class FragmentTestActivity extends Activity implements FragmentListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag(Fragment1.TAG) == null) {
fm.beginTransaction().replace(R.id.placeholder, new Fragment1(), Fragment1.TAG).commit();
}
}
#Override
public void onButtonClick() {
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag(Fragment2.TAG) == null) {
fm.beginTransaction().replace(R.id.placeholder, new Fragment2(), Fragment2.TAG).addToBackStack(Fragment2.TAG).commit();
}
}
}
Fragment1.java:
package fragmenttest.example.com;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class Fragment1 extends Fragment {
public static final String TAG = Fragment1.class.getName();
private FragmentListener mListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment1, container, false);
Button button = (Button) root.findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mListener.onButtonClick();
}
});
return root;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mListener = (FragmentListener) activity;
}
}
Fragment2.java:
package fragmenttest.example.com;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment2 extends Fragment {
public static final String TAG = Fragment2.class.getName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment2, container, false);
return root;
}
}
FragmentListener.java:
package fragmenttest.example.com;
public interface FragmentListener {
public void onButtonClick();
}
It may be because onCreate isn't called when restoring the fragment.
See:http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)