Accessing fragment's view from an activity - android

I have an activity that holds a fragment, it adds it by doing this in the onCreate (From a Google example):
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
RecordFragment firstFragment = new RecordFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
This is the activity layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
This is the Fragment:
public class RecordFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_record, container, false);
}
And the fragment_record.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.controlcenter.RecordActivity$PlaceholderFragment" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Information:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<EditText
android:id="#+id/action_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10" />
<ImageView
android:id="#+id/arrow_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/ic_action_forward" />
</LinearLayout>
In the fragment there is a arrow button. I want the activity to add a listener to the button so when it is clicked the fragment will slide out and another fragment will slide in.
Im having trouble accessing that button, I'm trying to use
firstFragment.getView().findViewById(R.id.arrow_button)
But it appears getView is returning null although I overload the onCreateView() method.

The simple answer is that you don't. Treat the Fragment's view as something that's internal to the fragment. Instead, set the activity as a listener to the Fragment via an interface you define and then set the click listener in the fragment to call the fragment's listener.
public class MyFragment extends Fragment {
public interface MyListener {
public void onAction();
}
private MyListener mListener;
public void setListener(MyListener listener) {
mListener = listener;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_record, container, false);
root.findViewById(R.id.arrow_button).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if (mListener != null) {
mListener.onAction();
}
}
});
return root;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof MyListener) {
mListener = (MyListener) activity;
} else {
// Maybe throw an exception if you want to be strict
}
}
}
And your Activity class would need this:
public class MyActivity extends Activity implements MyFragment.MyListener {
public void onAction() {
// TODO whatever you need to do when the button is clicked
}
}

Related

Changing fragments onClick of a button

I am trying to change the fragment when I click on a button. The button is inside a fragment and I want to go to another fragment. This code is not giving any error but not changing to desired fragment. It is just showing the background of container. Please help me why it is just showing the color of container and not changing to new fragment.
Here is my first Fragment-
public class IntroFragment1 extends Fragment {
public IntroFragment1() {
// Required empty public constructor
}
public static IntroFragment1 newInstance() {
return new IntroFragment1();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_intro1, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
/**
* Button to go to next tab in tutorial
* */
Button nextScreen = getView().findViewById(R.id.nextTabButtonIntro);
nextScreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (vb1 != null) {
vb1.vibrate(300);
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
Fragment frag = IntroFragment2.newInstance();
transaction.replace(R.id.containerIntroScreen, frag);
transaction.commit();
}
});
}//End of onViewCreated
}
This is the XML of first Fragment. The next Button should take me to next fragment-
<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="#color/colorPrimaryDark"
android:orientation="vertical"
android:weightSum="1"
tools:context="com.example.fitbitsampleapp.AppIntroTabbedView.IntroFragment1">
<TextView
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fontFamily="casual"
android:text="Track your daily activities. Stay healthy, Stay smart."
android:textSize="26dp" />
<Button
android:id="#+id/skipIntoButton"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:layout_weight="1"
android:background="#drawable/background_button"
android:fontFamily="casual"
android:text="skip"
android:textAllCaps="true"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Large"
android:textColor="#000" />
<Button
android:id="#+id/nextTabButtonIntro"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:layout_weight="1"
android:background="#drawable/background_button"
android:fontFamily="casual"
android:text="next"
android:textAllCaps="true"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Large"
android:textColor="#000" />
</LinearLayout>
This is the fragment, I want to go to-
public class IntroFragment2 extends Fragment {
public IntroFragment2() {
// Required empty public constructor
}
public static android.support.v4.app.Fragment newInstance() {
IntroFragment2 fragment = new IntroFragment2();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_intro2, container, false);
}
The XML of the 2nd Fragment-
<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"
android:background="#color/colorAccent"
tools:context="com.example.fitbitsampleapp.AppIntroTabbedView.IntroFragment2">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:text="2nd fragment" />
</RelativeLayout>
This is the layout of activity which has the fragments-
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.fitbitsampleapp.AppIntroTabbedView.IntroScreen">
<android.support.v4.view.ViewPager
android:background="#00F111"
android:id="#+id/containerIntroScreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
So initially the app opens with 1st transaction as expected. However when I click on next button in fragment 1, it should take me to fragment 2. But it just shows the Background color of ViewPager after the Fragment Transaction.
EDIT:
Here is my Main Activity as well which has the fragments-
public class IntroScreen extends AppCompatActivity {
public static Vibrator vb1;
public Button nextScreen;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intro_screen);
/***/
vb1 = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
/**
* Create the adapter that will return a fragment
* for each of the N primary sections of the activity.
* */
SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
/** Set up the ViewPager with the sections adapter.*/
ViewPager mViewPager = findViewById(R.id.containerIntroScreen);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
switch (position) {
case 0:
return IntroFragment1.newInstance();
case 1:
return IntroFragment2.newInstance();
default:
return IntroFragment2.newInstance();
}
}
#Override
public int getCount() {
return 2;
}
}
}
SOLVED BY #MikeM. in the comments above.
Since I was already using a ViewPager, All that was required was to give the correct item number to my ViewPager.
int THE_POSITION_OF_THE_FRAGMENT_IN_VIEW_PAGER = 1;
mViewPager.setCurrentItem(THE_POSITION_OF_THE_FRAGMENT_IN_VIEW_PAGER);

Android. Get listview item onClick inner button to new child fragment

I have a Fragment with a ListView of row items. A row consist in just am ImageView
fragment_1.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment1">
<ListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#b5b5b5"
android:dividerHeight="1dp"
android:listSelector="#drawable/list_selector"/>
</RelativeLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/row"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/list_selector"
android:orientation="horizontal"
android:padding="5dip">
<!-- Rightend Play Button. -->
<ImageView
android:id="#+id/play_button"
android:layout_width="50dip"
android:layout_height="50dip"
android:src="#drawable/ic_play"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>
</RelativeLayout>
I have a ResourceCursorAdapter to fill this ListView. I just assign to each ImageView a click listener. It plays a record saved in the provided path.
private abstract class MyAdapter extends ResourceCursorAadpter {
#Override
public void bindView(View view, Context context, final Cursor cursor) {
// Play button.
ImageView playButton = (ImageView) view.findViewById(R.id.play_button);
playButton.setOnClickListener(new View.OnClickListener() {
String record = cursor.getString(cursor.getColumnIndex(DbAdapter.RECORD));
public void onClick(View v) {
// Play record in path [record]. Not the problem.
}
});
}
}
Now I want to open a new fragment Fragment_2 in a row click. This fragment has the same play_button, and has to play the same record.
fragment_2.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_audio"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment2">
<!-- Play Button. -->
<ImageView
android:id="#+id/play_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/ic_play"/>
</RelativeLayout>
How can I manage that this button plays the same record than in Fragment_1? I think I could be able if I have a hidden TextView with the path of the record, but sure you have a smarter solution.
In my onCreateView of Fragment_1.
mList = (ListView) root.findViewById(R.id.list);
// Click event for single row.
mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO: Go to fragment_2 and has the same view [view.findViewById(R.id.play_button)]
}
});
Communication between fragments should be done through the associated Activity. You can use interface for this. it Will serve as contract and bridge between them.
Let's have the following components:
An activity hosts fragments and allow fragments communication
FragmentA first fragment which will send data
FragmentB second fragment which will receive datas from FragmentA
FragmentA's implementation is:
public class FragmentA extends Fragment {
DataPassListener mCallback;
public interface DataPassListener{
public void passData(String data);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Make sure that container activity implement the callback interface
try {
mCallback = (DataPassListener)activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement DataPassListener");
}
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Suppose that when a button clicked second FragmentB will be inflated
// some data on FragmentA will pass FragmentB
// Button passDataButton = (Button).........
passDataButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (view.getId() == R.id.passDataButton) {
mCallback.passData("Text to pass FragmentB");
}
}
});
}
}
MainActivity implementation is:
public class MainActivity extends ActionBarActivity implements DataPassListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.container) != null) {
if (savedInstanceState != null) {
return;
}
getFragmentManager().beginTransaction()
.add(R.id.container, new FragmentA()).commit();
}
}
#Override
public void passData(String data) {
FragmentB fragmentB = new FragmentB ();
Bundle args = new Bundle();
args.putString(FragmentB.DATA_RECEIVE, data);
fragmentB .setArguments(args);
getFragmentManager().beginTransaction()
.replace(R.id.container, fragmentB )
.commit();
}
}
FragmentB implementation is:
public class FragmentB extends Fragment{
final static String DATA_RECEIVE = "data_receive";
TextView showReceivedData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_B, container, false);
showReceivedData = (TextView) view.findViewById(R.id.showReceivedData);
}
#Override
public void onStart() {
super.onStart();
Bundle args = getArguments();
if (args != null) {
showReceivedData.setText(args.getString(DATA_RECEIVE));
}
}
https://developer.android.com/training/basics/fragments/communicating.html
This document has given information in detail, you can go through it.
In your situation, you can apply this way to communicate between two fragments.

Fragment's onDestroyView called but view is not being destroyed

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();
}

On android, when I set the Text of a TextView dynamically it doesn't change

I am new to the android platform so I know I am just missing something by here is what I have
<!-- activity_main -->
<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.example_app.MainActivity"
tools:ignore="MergeRootFrame" >
<fragment
android:id="#+id/mainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.example_app.MainFragment"
/>
</FrameLayout>
Then I created a fragment called MainFragment.java.
public class MainFragment extends Fragment {
public TextView displayTextView;
public MainFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
this.displayTextView = (TextView)rootView.findViewById(R.id.displayTextView);
return rootView;
}
}
I add the fragment in the OnCreate function in the activity and it seems to be adding everything okay but when I click on the button nothing happens, I logged the function to see its being called but setting the textview doesn't do anything. What am I doing wrong?
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.example_app.MainActivity$PlaceholderFragment" >
<Button
android:id="#+id/button10"
android:textColor="#ffffff"
android:textSize="34dp"
android:text="10%"
android:layout_below="#id/amountEditText"
android:background="#drawable/pct_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doSomething"
/>
<TextView
android:text="Blah Blah Blah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/displayTextView"
></TextView>
</RelativeLayout>
And here is the click Event in the MainActivity.java
public void doSomething(View v) {
this.mainFragment.displayTextView.setText("Nothing to set for some reason!");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
//
this.mainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.mainFragment);
mainFragment = new MainFragment();
getSupportFragmentManager().beginTransaction().add(mainFragment, "mainFragment").commit();
}
}
Declaring onClick-Listeners via XML is possible if you work with Activities. According to the Google API, however, you need to declare OnClickListeners programmatically if you use Fragments.
[...] You can also declare the click event handler programmatically rather than in an XML layout. This might be necessary if you instantiate the Button at runtime or you need to declare the click behavior in a Fragment subclass.
Source:
http://developer.android.com/guide/topics/ui/controls/button.html
So you may want to use this instead:
public class MainFragment extends Fragment {
public TextView displayTextView;
public Button yourButton;
public MainFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
this.displayTextView = (TextView)rootView.findViewById(R.id.displayTextView);
yourButton = (Button)rootView.findViewById(R.id.button10);
yourButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
displayTextView.setText("Nothing to set for some reason!");
}
});
return rootView;
}
}
The problem is the way you try to execute the button click. From your question i understand that Button and TextView is in Fragment view. So do why are Trying to access it in activity ?? It is wrong, then there is no point of using Fragments. Also this will lead to many serious issues later .
Fragments are Reusable components so all the functionalities of a fragment must stay inside the Fragment Class
Change Fragment code :
public class MainFragment extends Fragment {
public TextView displayTextView;
public Button yourButton;
public MainFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
this.displayTextView = (TextView)rootView.findViewById(R.id.displayTextView);
yourButton = (Button)rootView.findViewById(R.id.button10);
//Setting click listener for button in fragment
yourButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
displayTextView.setText("Nothing to set for some reason!");
}
});
return rootView;
}
}
and remove android:onClick="doSomething" from XML

Passing data between two fragments in two different activities

I am trying to do a very basic example with Fragments.
Structure : Fragment1 -> Fragment1Activity, Fragment2 -> Fragment2Activity.
Both activities have a STATIC Fragment in it.
Here are the XMLs:
activity_for_fragment_1.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.xx.fragmentstutorial1.Fragment1"
tools:context="com.xx.fragmentstutorial1.Fragment1Activity"/>
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" >
<TextView
android:id="#+id/textview_fragment_1"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="0.60"
android:text="This is Fragment 1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="#+id/edittext_fragment_1_text"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="0.20"
android:text="Type your message here..." >
<requestFocus />
</EditText>
<Button
android:id="#+id/button_fragment_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Me" />
</LinearLayout>
activity_for_fragment_2.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.xx.fragmentstutorial1.Fragment2"
tools:context="com.xx.fragmentstutorial1.Fragment2Activity"/>
fragment_2.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/textview_fragment_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="This is Fragment 2"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/textview_fragment_2_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="I will display text from \nFragment 1"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
Now, I have an Edittext and button in the fragment_1. When I click on the button, I want to get the text entered in EditText and set it to the textview(textview_fragment_2_result) in fragment_2
I was able to achieve this, but, I am not very convinced, that the approach I took was good enough. Please look at the java code below..
Fragment1Activity.java
public class Fragment1Activity extends SherlockFragmentActivity implements Fragment1.ButtonClickListener{
Fragment1 fragment1;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_for_fragment_1);
System.out.println("onCreate Fragment1Activity");
fragment1 = (Fragment1) getSupportFragmentManager().findFragmentById(R.id.fragment_1);
}
#Override
public void onButtonClick(String message) {
System.out.println("onButtonClick Fragment1Activity");
startActivity(new Intent(this, Fragment2Activity.class).putExtra("message", message));
}
}
Fragment1.java
public class Fragment1 extends SherlockFragment {
EditText message;
Button clickme;
ButtonClickListener listener;
public interface ButtonClickListener{
public void onButtonClick(String message);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof ButtonClickListener)
listener = (ButtonClickListener) activity;
else {
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
System.out.println("onCreateView Fragment1");
View view = inflater.inflate(R.layout.fragment_1, container, false);
message = (EditText) view.findViewById(R.id.edittext_fragment_1_text);
clickme = (Button) view.findViewById(R.id.button_fragment_1);
clickme.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (!message.getText().toString().equalsIgnoreCase("")) {
System.out.println("Message in Fragment1 = "+message.getText().toString());
listener.onButtonClick(message.getText().toString());
} else {
Toast.makeText(getActivity(),
"Please enter some message...", Toast.LENGTH_LONG)
.show();
}
}
});
return view;
}
}
Fragment2Activity.java
public class Fragment2Activity extends SherlockFragmentActivity {
Fragment2 fragment2;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_for_fragment_2);
fragment2 = (Fragment2) getSupportFragmentManager().findFragmentById(R.id.fragment_2);
fragment2.setMessage(getIntent().getExtras().getString("message").toString());
}
}
Fragment2.java
public class Fragment2 extends SherlockFragment {
String msg;
TextView textview;
public Fragment2() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_2, container, false);
textview = (TextView) view
.findViewById(R.id.textview_fragment_2_result);
textview.setText(msg);
return view;
}
public void setMessage(String message) {
msg = message;
textview.setText(msg);
}
}
I have set the text for textview in setMessage() of Fragment2.java, which I think is not a good approach. If i comment that out, I don't see any text in the textview of Fragment2.
Can someone help me out, on how to pass values between two static fragments correctly.
You should go with interface
Follow the Diagram Here :
Communication Between Two Fragment is Done Via Activity using Interface
Fragment A-------------------------->Activity-------------------->Fragment B
(defines Interface) (Implement interface) (pass it other Fragment B)
Hope this could help
Check This Out
What you have is mostly good. The part of transferring the data from Fragment1 to Activity1 is good. Once the data gets to Activity2, you are setting it in Fragment2. I would change this part a little.
In Activity2:
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_for_fragment_2);
fragment2 = (Fragment2) getSupportFragmentManager().findFragmentById(R.id.fragment_2);
fragment2.setArguments(getIntent().getExtras());
}
and in Fragment2.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle bundle = getArguments();
String message = bundle.getString("message");
View view = inflater.inflate(R.layout.fragment_2, container, false);
textview = (TextView) view
.findViewById(R.id.textview_fragment_2_result);
textview.setText(message);
return view;
}
Your approach seems correct. The connection between your Fragment1 and Activity1 is just like in the fragments guideline. Your fragment1 shouldn't know about fragment2 therefore it's OK to pass the responsibility to the fragment's container/parent - activity1 - that knows what to do with the data. This time again your approach is correct - activity1 starts it's slave/child etc. and is responsible to start it with correct data (passed through the intent extras). And then again you have a correct approach - when your activity2 is created you populate it's views with the appropriate content/data (the message) that was meant to be displayed in this activity and given to it by the "parent" activity.

Categories

Resources