I have ActivityA which contains FragmentA inside it. How to access the TextView in the activity from the Fragment.
Override onViewCreated() method inside your Fragment class and use the Fragment View to declare the TextView:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ActivityA.text_view= (TextView) view.findViewById(R.id.text_view); // your TextView must be declared as (public static TextView text_view) in the Activity
// now access the TextView as you want
}
The easiest way is to create a getter method inside your Mainactivity that returns your textview and access it by casting your fragment's activity to your Mainactivity.
So in your Mainactivity,
public AppCompatTextView getMyTextView(){
return myTextView;
}
And in your Fragment
((MainActivity)getActivity()).getMyTextView()
And do whatever you please with it.
You can either use callbacks or make your fragment as an inner class.
For callbacks you need to implements some interface in your activity let say you want to update your TextView and in the onAttach method of the fragment you can then use the reference of that interface to communicate with the activity.
sample:
in activity:
public class Question implements MyInterFace
in fragment:
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
youInterfaceObject = (MyInterFace)activity;
super.onAttach(activity);
}
For inner class it is just easy just create a global variable of the TextView in your activity and call it from the inner class.
May not work for views, but give it a try:
((MainActivity) getActivity()).textViewName;
Related
I have a fragment which has a TextView, an EditText and a Button. I also have 2 activities which include this fragment and at onClick of the button in one of the activities, the other is started. Via the intent, the text in the edittext is passed which becomes the text of the textview of the other activity.
I had two design decisions to choose from
Create two such fragments classes with appropriate methods that construct the appropriate intents. Access the UI elements from inside the respective fragment object and start the activities.
Create only one fragment class. onClick the, event is passed down to a particular method in the activities (both the activities have this method) and the activities have the logic to build the intent and start the other activity
Consider what would happen if there are 100 such activities. The first method would have us write 100 different fragment classes with custom methods, but in the second method, it is a single class and the activities have the custom logic in a particularly named method.
Therefore I chose to go with the second choice and I realized that the UI elements could not be instantiated in the onCreate method of activity as the fragment's layout is not inflated yet. I am doing the instantiation in onStart as a workaround.
Is that bad practice or is there a better design pattern to follow?
The recommended pattern is to create a holder interface which any activity that wants to instantiate your fragment must implement. Also to set data for views in your new fragment then create a newInstance() factory method on your fragment.
I tend to approach it like this;
class FooFragment implements Fragment {
private static final String TEXT_FOR_TEXTVIEW = "textForTextView";
private FooFragmentHolder mHolder;
/*
* Rather than creating your fragment in your layout directly
* you should instead instantiate it using this class in your
* activity.
*/
public static FooFragment newInstance(String text) {
Bundle data = new Bundle();
data.putString(TEXT_FOR_TEXTVIEW, text);
FooFragment fooFragment = new FooFragment();
fooFragment.setArguments(data);
return fooFragment;
}
public interface FooFragmentHolder {
public void buttonPressed(String editTextContent);
}
/*
* When we create the fragment with the activity we use onAttach to get
* our holder implementation (the activity)
*/
#Override
public void onAttach(Activity activity) {
if (activity instanceof FooFragmentHolder) {
mHolder = (FooFragmentHolder) activity;
} else {
throw new IllegalStateException("Containing activity must implement FooFragmentHolder");
}
}
#Override
public void onCreateView(Inflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_foo, container, false);
final EditText editText = (EditText) view.findViewById(R.id.edit_text);
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(Button button) {
mHolder.buttonPressed(editText.getText());
}
})};
TextView textView = (TextView) view.findViewById(R.id.text_view);
Bundle args = getArguments();
if (args != null) {
textView.setText(args.getString(TEXT_FOR_TEXTVIEW));
}
return view;
}
}
Now in your activity you just need to implement the FooFragmentHolder interface and use the newInstance method we created;
class FooActivity extends Activity implements FooFragment.FooFragmentHolder {
private static final String TEXT_FOR_TEXTVIEW = "textForTextView";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentLayout(R.layout.activity_foo);
// Instead of creating your fragment in your layout, create a holder
// layout and attach a new instance of your fragment using a fragment
// transaction.
FooFragment fooFragment = FooFragment.newInstance(getIntent().getStringExtra(TEXT_FOR_TEXTVIEW));
getFragmentManager().beginTransaction()
.replace(R.id.content, fooFragment)
.commit();
}
#Override
public void buttonPressed(String editTextContent) {
// In this case just starting the next FooActivity, but logic could be
// applied for any other activity.
Intent intent = new Intent(this, FooActivity.class)
.putExtra(TEXT_FOR_TEXTVIEW, editTextContent);
startActivity(intent);
}
}
I decided to settle with the following patter --
Any activity which includes this fragment should implement an interface like
public interface ViewsCreatedListener {
public void onViewsCreated();
}
The activity would then look like
public class ExampleActivity extends Activity implements ViewsCreatedListener {
.
.
.
.
#Override
public void onViewsCreated() {
//Initiate the views here and do what gotta be done
}
}
The fragment should check that any activity that includes this fragment should implement that interface using the onAttach method and onActivityCreated, the activity is notified
public class ExampleFragment extends Fragment {
ViewsCreatedListener listener = null;
.
.
.
.
#Override
public onAttach(Activity activity) {
super.onAttach(activity);
try {
listener = (ViewsCreatedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement ViewsCreatedListener");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listener.onViewsCreated();
}
}
Doing this way, the fragment just provides the UI and the including activities decide as to what should be done with the UI elements included via the fragment. This maximizes reusability.. DRY... :-D
I have two fragments sitting side by side in the same activity. When I touch a button in the right fragment (fragment B), I need a TextView in the left fragment to update (fragment A). I have looked all over for the best way to do this, but nothing seems to work for my needs. Could someone possibly give me an example of how I would code this? Fragment A is set through the XML layout, and fragment B gets loaded programmatically into a container. I have tried accomplishing this by using a method in fragment A to update the text, and calling on that method from a method in the parent activity. I then call on the method in the parent activity from fragment B.
This is the code in fragment B that declares the interface and calls a method in the interface
AttackCards attackCards;
public interface AttackCards {
public void deckSize();
}
public void onAttach(DeckBuilder deckBuilder) {
super.onAttach(deckBuilder);
attackCards = (AttackCards) deckBuilder;
}
attackCards.deckSize(); //this is in my onclick methods
This is the code in the activity that implements the interface and calls the method in fragment A
public class DeckBuilder extends Activity implements AttackCards{
public void deckSize() {
DeckBuilderFragment deckBuilderFragment = (DeckBuilderFragment)getFragmentManager().
findFragmentById(R.id.deckbuilder_fragment);
deckBuilderFragment.deckSize();
}
This is the method in fragment A that appends the textview with the contents of a shared preferences value
public void deckSize() {
deckSize = (TextView) getView().findViewById(R.id.decksize);
final SharedPreferences defaultDeck = getActivity()
.getSharedPreferences("defaultDeck", Context.MODE_PRIVATE);
deckSize.setText(String.valueOf(defaultDeck.getInt("decksize", 0)));
}
Sadly this attempt simply brings me a nullpointer when touching a button. I am getting a null pointer at
attackCards.deckSize(); //this is in my onclick methods
Could someone please help me out with an example of how to do this correctly?
One fragment should not communicate to another fragment directly. It should do so through attached activity. The detail explanation with code example is available here
Android Developer site
Declare an interface in Fragment B, and implement the interface in the activity. Call the interface through callback in Fragment B when button is clicked. You can have a public function in Fragment A to update the TextView, so activity directly call the function to update the text.
You can define an interface in Fragment B and implement it on the MainActivity. Then on the callback method (onClickOnB in this case) set the text on the TextView. You should obtain a reference of the TextView in the Activity's onCreate() after setContentView(). This works because Fragment A is static. Otherwise, you can create a public method inside Fragment A so you can set the text from inside the callback by getting a reference of Fragment A and calling such method.
Fragment B
public class FragmentB extends Fragment implements onClickListener{
ClickOnB listener;
public void setOnFragmentBClickListener(ClickOnB listener){
this.listener = listener;
}
#Override
public void onClick(View v){
//stringMessage is a `String` you will pass to `Fragment` A to update its `TextView`
listener.onClickOnB(stringMessage);
}
interface ClickOnB{
public void onClickOnB(String message);
}
}
MainActivity
public class MainActivity extends Activity implements ClickOnB{
#Override
protected onCreate(Bundle savedInstanceState){
//Get a reference of `Fragment` B somewhere in your code after you added it dynamically and set the listener.
((FragmentB)getFragmentManager().findFragmentByTag("FragmentB")).setOnFragmentBClickListener(this);
}
#Override
public void onClickOnB(String message){
//Set the text to the `TextView` here (I am assuming you get a reference of the `TextView` in onCreate() after inflating your layout.
mTextView.setText(message);
}
}
Ive asked a similar question before and didn't get an answer and seems many other ppl are searching for an answer. So I am posting this question to hopefully get a clear answer that everyone can benefit from.
I have an activity with 2 fragments in it. I want fragment2 to set a boolean variable in Activity when a checkbox is checked so that fragment1 can know if the checkbox was checked.
This is my Code:
Activity:
public class modestab extends Activity{
public static Context appContext;
public boolean lf=false;
public void onCreate(Bundle savedInstanceState){
appContext=this;
super.onCreate(savedInstanceState);
ActionBar tabbar= getActionBar();
tabbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab ModesTab =tabbar.newTab().setText("Modes");
ActionBar.Tab CatTab =tabbar.newTab().setText("Categories");
Fragment ModesFragment =new modes();
Fragment CatFragment =new cats();
ModesTab.setTabListener(new MyTabsListener(ModesFragment));
CattTab.setTabListener(new MyTabsListener(CatFragment));
tabbar.addTab(ModesTab);
tabbar.addTab(CatTab);
}
Fragment 1:(Where I want to read the boolean lf set in Acitivity above:
#TargetApi(11)
public class tabmodes extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View V=inflater.inflate(R.layout.tab_modes, container, false);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(lf==false) //lf here is the lf in Activity which I want to get
Fragment 2: Where I want to set lf in Activity
.....
lifecheck.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(lifecheck.isChecked())
getActivity().lf=true;//Where I want to set the lf flag in Activity
;
}
});
The code doesn't compile and I am not knowing how to set lf in the Activity nor how to read it. Someone suggested I do getActivity() but I am not able to see the variable.
I tried to create a function setlf(boolean jk) but also I am not able to see it...
Any help is welcome :)
Many ways :
1) Activity -> Fragment
In your Activity : create a bundle and use fragment.setArguments(bundle)
in your Fragment : use Bundle bundle = getArguments()
2) Activity -> Fragment
In your Fragment : create a public method
In your Activity : call an active fragment public method :
getSupportFragmentManager().findFragmentById(R.id.your_fragment).publicMethod(args)
3) Fragment -> Activity
In your Fragment : create un interface with getter and setter methods (callback methods)
In your Activity : implement the interface
4) Fragment -> Activity
In your Activity : Create public getter and setter or other methods
In your Fragment : called public activity getter, setter or other methods using :
getActivity().getSomething(), getActivity().setSomething(args) or getActivity().someMethod(args)
You can pass data between fragments in two ways,
First, you can do it by using setArguments(...) and getArguments(....)
Second,you can do it using Call back
Also you can use EventBus. It's really simple.
https://github.com/greenrobot/EventBus
Definitely don't use static methods like my old answer :)
i have code like this
public class fragment2 extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.content, container, false);
}
}
i want to call activity class instead of layout.
please help me.
Following link talks about communication between two fragment via activity..
http://developer.android.com/training/basics/fragments/communicating.html
same example can be used to communicate back to the activity from fragment.
For example if you have activity and fragment called MyActivity and MyFragment,
you can provide some public method in MyActivity. After this in the MyFragment#onCreateView()
you can call
String layout = ((MyActivity)getActivity()).getMyLayoutLink()
You could create an interface in the fragment, then implement it in the activity. You then set the listener in the fragments onAttach() method. This is called before onCreateView(). This pattern makes your code reusable and this technique can apply for all your activities and fragments they use. Example code for the fragment:
public class YourFragment extends Fragment {
private OnItemSelectedListener onClickListener;
public interface OnItemSelectedListener {
//implement and use this function in your calling activity
public void yourItemSelected(String link);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//check that the activity implements the interface
if (activity instanceof OnItemSelectedListener) {
//set the listener to the calling activity
onClickListener = (OnItemSelectedListener) activity;
} else {
throw new ClassCastException(activity.toString()
+ " must implement YourFragment.OnItemSelectedListener");
}
}
}
For more info see the android documentation:
http://developer.android.com/training/basics/fragments/communicating.html
http://developer.android.com/guide/components/fragments.html#Lifecycle
Let's say I have this button:
<Button
android:id="#+id/idone"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="D2"
android:onClick="myMeth"/>
I have several times used this to call methods from a layout xml as it calls the method from the activity that inflated such view.
Recently with DialogFragments, well it does not work at all. I keep getting an error telling me that such method does not exist. Where is it then looking for such method? I have added it to the DialogFragment class:
public class myActivity extends DialogFragment {
public DiceDialog() {
// empty constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.myDialog, container);
getDialog().setTitle("Hello");
return view;
}
public void myMeth(View view) {
//...
}
As well as in the activity that instantiates the FragmentManager and calls the dialog:
public Class MainActiviry Extends FragmentActivity {
//...
public void onCreate(Bundle savedInstanceState) {
// ..
FragmentManager fm = getSupportFragmentManager();
MyActivity dialog = new AddDiceDialog();
dialog.show(fm, "tag");
}
public void myMeth(View view){
//...
}
And still the messag is that MyMeth is not found.
I have already read that using interfaces and listeners is the correct way to communicate between activity and dialog fragments, but what I am trying to figure out here is where that myMeth call is being made, because well,it is called.
You can implement public myMeth(View view) in your Activity, which will then check for the currently visible Fragment, and call its method.
If you want to use more then one callable method in your Fragment, you can utilize the id's of the calling views and implement a switch, calling a different fragment method according to the id of the View.