I have a Main Activity having one edittext and a viewpager which is getting inflated via two fragments. Both fragment layout contain buttons. My question is how to fire their on click listener in main activity.
Like i have a button in one fragment which should change the text in my edittext bold using spannable string. I can achieve it if all of this is in my main activity. My question is how to capture the listener of this button in main activity ?
Create one interface and pass the instance to fragment and when button clicked from fragment call the method of interface so you will get callback to activity and from there you can update your UI.
for example:
public interface MyInterface {
public void buttonClicked();
}
public class Activity implements MyInterface {
#override
public void buttonClicked() {
//Change the UI
}
}
public class MyFragment extends Fragment {
MyInterface interface;
public void setInterface(MyInterface interface) {
this.interface = interface;
}
public void onClick(View v) {
interface.buttonClicked();
}
}
In your fragment, you can use
((MainActivity)getActivity()).myMethod()
to call myMethod of MainActivity. This solution assumes, that your fragment is located in MainActivity (getActivity must return MainActivity instance) :-)
Related
I am new in Android development. I want to add a listener in my fragment which upon button click will send a message. I need to listen to this in my main fragment class so that my activity can access this main fragment and process the message. I also need to remove the listener in my main fragment. So how do I implement this?
EDIT
I have MyFragment
sendMessage(message) is a method in MyFragment which has a button click. Need to implement listener here?
In MainFragment
How to handle this sendMessage event here and send to MAinActivity
The flow is like MyFragment(childfragment) -> MAinFragment -> MainActivity
In your fragment class, say MyFragment.java create an interface
public interface MyFragmentInterfacer{
void onButtonClick(String msg);
}
MyFragmentInterfacer fragmentInterfacer;
//Override this function as below to set fragmentInterfacer
#Override
public void onAttach(Context context){
fragmentInterfacer = (MyFragmentInterfacer)context;
}
and where you want to invoke this function
myButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
if(fragmentInterfacer != null){
fragmentInterfacer.onButtonClick("This is my Message");
}
}
});
Then in your main activity where you want to get this message, implement this interface
public class MainActivity implements MyFragment.MyFragmentInterfacer{
.
.
}
and then implement the interface function in MainActivity
#Override
public void onButtonClick(String msg){
//Do something with this message
}
To remove this listener, use
fragmentInterfacer = null;
in your fragment class when you want to disable this listener.
Or you can remove the onClickListener from button
myButton.setOnClickListener(null);
or disable clicking on button
myButton.setClickable(false);
Can someone please tell me if I'm solving this correctly or if I should go another route?
This is a simplified example: I have 1 Activity and 2 Fragments. Each Fragment has a button that when clicked, relays the click back to the Activity and a Toast pops up within the Activity.
I know that a Fragment communicates with an Activity through an interface. But what If I have multiple Fragments that have a similar Interface. For example, here both Fragments use an onClick type of interface to communicate back to the Activity
static interface OnClickedListener{
public void buttonClicked(View v);
}
Is it better to
A) Create a separate Interface class and attach it within both Fragments. For example Fragment 1:
public class Fragment1 extends Fragment implements OnClickedListener{
private OnClickedListener clickedInterface;
public Fragment1() {
// Required empty public constructor
}
#Override
public void buttonClicked(View v) {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.clickedInterface = (OnClickedListener)activity;
}}
Fragment 2:
public class Fragment2 extends Fragment implements OnClickedListener{
private OnClickedListener clickedInterface;
public Fragment2() {
// Required empty public constructor
}
#Override
public void buttonClicked(View v) {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.clickedInterface = (OnClickedListener)activity;
}
OR
B) Create individual Interfaces unique to the specific Fragment and implement those in the MainActivity instead of the one Interface like mentioned above. Thank you.
First Create your custom fragment which is in implement interface.
public class CustomFragment extends Fragment implements OnClickedListener{
public OnClickedListener clickedInterface;
#Override
public void buttonClicked(View v) {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.clickedInterface = (OnClickedListener)activity;
}
}
Now, you can add in every fragment
(i) Fragment 1
public class Fragment1 extends CustomFragment {
......
}
(ii) Fragment 2
public class Fragment2 extends CustomFragment {
......
}
I wouldn't let the details of any Views contained in a Fragment leak out into the Activity.
Better interfaces would be based on the semantic action involved with the button press, for example createThing() or deleteThing().
The Activity shouldn't really care which View was clicked to initiate the action just that the action needs to happen. When happens to your interfaces if you move the button to the menu, or somewhere else not associated with a View.
If you create interfaces like this, the question of creating copies for different Fragments disappears.
There is a code principal called SOLID. "I" states for https://en.wikipedia.org/wiki/Interface_segregation_principle. It is a good practice to
You should not make universal interface or large ones, you need to create interface that can be "readable" and "understandable" for everyone by interface name and its method names like "articleSelected" or "loginProcessing(String loginName)" etc
In my main Activity, I have a DialogFragment that contains a FragmentTabHost. I have two tabs, one that is a DialogFragment and one that is a ListFragment. When either the 'OK' button is pressed in the inner DialogFragment or when an element in the ListFragment is pressed, I want to pass two Strings (that are entered in two TextView's in the inner DialogFragment and are displayed in each element in the ListFragment) back to the Activity, but I am unsure of how to do this with multiple levels of Fragments.
Any help is appreciated!
There's no magic.
You can achieve with two approaches.
Use callback.
Create interface and class to pass the data through child Fragment to Activity. You don't need to modify bridged TabHostFragment as Fragment always rely on its mother Context (Activity) no matter how many fragments wrap the fragment.
public class TwoStrings {
public TwoStrings(String one, String two){
this.one = one;
this.two = two;
}
public String one;
public String two;
}
First, declare interface.
public interface DataPassListener {
void dataPassed(TwoStrings data);
}
And, implement interface in Activity.
public class MainActivity extends Activity implements DataPassListener {
#Override
public void dataPassed(TwoStrings data) {
// do something with data.
Log.d("string one", data.one);
Log.d("string two", data.two);
}
}
Finally, let child Fragment acknowlege that mother Activity has the callback listener.
public class DialogFragment1 extends DialogFragment {
DataPassListener listener;
#Override
public void onAttach(Activity activity) {
if (activity instanceOf DataPassListener)
listener = (DataPassListener) activity;
}
public void setDataPassListener(DataPassListener listener){
listener = ((DataPassListener) listener);
}
public void doSomeThing(){
if(listener != null) // important to prevent NullPointerException
listener.dataPassed("a", "b");
}
}
Use EventBus.
I prefer to use Otto in order to publish and subscribe data.
To subscribe event for listening in Activity,
public class MainActivity extends Activity {
#Override
public void onResume() {
super.onResume();
BusProvider.getInstance().register(this);
}
#Override
public void onPause() {
super.onPause();
BusProvider.getInstance().unregister(this);
}
#Subscribe
public void onUpdateTwoStrings(TwoStrings event) {
// do something with data.
Log.d("string one", data.one);
Log.d("string two", data.two);
}
}
And, publish event in anywhere in Fragment.
bus.post(new TwoStrings("a", "b"));
Take a look at setTargetFragment() and getTargetFragment() methods. You could connect fragments with each other through it without any additional callbacks and libs.
Please please don't minus my question i confused when googling.
I used Android Tab Layout with Swipeable Views in my code for when user pressed setting button on an activity.
now I need send message from TopRatedFragment.java that extends from fragment to the activity that call the mainActivity of "Android Tab Layout with Swipeable Views".
You can do this by implementing a call back
create an interface first
public interface CommunicationInterface {
public void onSuccess();
public void onFailed();
}
then in your activity implement the interface
public class YourActivity extends ActionBarActivity implements CommunicationInterface {
//default functions
#Override
public void onSuccess() {
//stuff you want to do in the acivity
}
#Override
public void onFailed() {
//stuff you want to do in the acivity
}
}
Now in the fragment
public class yourfragment extends Fragment {
CommunicationInterface callback;
//stuffs that usually come in yor fragment and like OncreateView etc
#Override
public void onActivityCreated(#Nullable Bundle outState) {
super.onActivityCreated(outState);
//after all the stuff you want to do in your fragment then implement //call back function to communicate with the activity
callback= (CommunicationInterface) getActivity();
callback.onSuccess();//according to your purpose use where ever you like
callback.onFailed();//according to your purpose use where ever you like
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
callback= (CommunicationInterface) activity;
}
}
Take a close look on this reference:
Creating event callbacks to the activity
The android docs recommend using this pattern of having the parent activity implement an interface of the fragment (Basically calling methods on it)
class MyFragment extends Fragment {
interface Listener {
public void onSomeEvent();
}
private void somethingHappeninInTheFragment() {
// let the activity know
((Listener) getActivity()).onSomeEVent();
}
}
class MyActivity extends Activity implements MyFragment.Listener {
// etc
#Override
public void onSomeEvent() {
// handle the message from the fragment
}
}
Explained with a more concrete example here: http://developer.android.com/guide/components/fragments.html#EventCallbacks
Here's the solution:
Step 1 : From your fragment.
Intent i = new Intent(getActivity(), YourActivity.class);
i.putExtra("key", "Your value1");
i.putExtra("key2", "Your value2");
i.putExtra("key3", "Your value3");
getActivity().startActivity(i);
Step 2 : In your Activity where you want the result
Intent getResults = getIntent();
String firstValue = getResults.getStringExtra("key1");
String secondValue = getResults.getStringExtra("key2");
String thirdValue = getResults.getStringExtra("key3");
Use those values your needs are.
Hope this helps.. :)
I have two Fragments in my Activity: fragment A with button X and fragment B with button Y.
How can I change button X's background image when I click button B? Is it possible?
From the documentation,
Because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment.
That being said, what you want to do is create event callbacks to the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary. This is the recommended way to share events between two separate Fragments--that is, sharing the event through the activity.
Check out the link above... it provides a couple nice examples. If you are still having trouble, let me know and maybe I can be more explicit.
Edit #1:
Let's say you click a button in fragment A and you want this to cause changes to a button in fragment B. Here's some sample code illustrating the concept:
The callback interface:
public interface OnButtonClickedListener {
public void onButtonClicked();
}
The activity:
public class SampleActivity extends Activity implements OnButtonClickedListener {
/* Implementation goes here */
public void onButtonClicked() {
// This method is called from fragment A, and when it is called,
// it will send information to fragment B. Remember to first
// check to see if fragment B is non-null.
/* Make call to a method in fragment B that will update its display */
}
}
Fragment A:
public class FragmentA extends Fragment {
OnButtonClickedListener mListener;
/* Implementation goes here */
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnButtonClickedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnButtonClickedListener ");
}
}
public void clickButton() {
// When the button is clicked, notify the activity.
// The activity will then pass the information to fragment
// B (if it has been created).
mListener.onButtonClicked();
}
}
Edit #2:
Now, you might be wondering, "Why would anyone ever go through all of this trouble? What's the point of creating a separate activity callback method when you could just have fragment A directly manipulate fragment B?"
The main reason you want to do this is to ensure that each fragment is designed as a modular and reusable activity component. This is especially important because a modular fragment allows you to change your fragment combinations for different screen sizes. When designing your application to support both tablets and handsets, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when more than one cannot fit within the same activity. Making use of activity callbacks ensures that you will easily be able to reuse your fragments in situations where fragment B is not visible on the screen. For example, if you are on a handheld device and there is not enough room to display fragment B, then you can easily have your activity check to see if fragment B is currently being shown on the screen.
Sorry if this isn't clear... I'm finding it difficult to describe :P. Working your way through this tutorial might help... Activity callbacks make your life especially easier as a developer when you are working with interactive multi-pane layouts.
Base on Alex Lockwood's answer:
The activity:
public class SampleActivity extends Activity{
public interface OnButtonClickedListener {
public void onButtonClicked();
}
private OnButtonClickedListener onButtonClickedListener = null;
public OnButtonClickedListener getOnButtonClickedListener () {
return onButtonClickedListener
}
public void setOnButtonClickedListener (
OnButtonClickedListener onButtonClickedListener {
this.onButtonClickedListener = onButtonClickedListener;
}
}
Fragment A:
public class FragmentA extends Fragment {
private OnButtonClickedListener onButtonClickedListener = null;
private OnClickListener actionBarClickListener = new OnClickListener() {
#Override
public void onClick(View view) {
if (onButtonClickedListener == null){
onButtonClickedListener = ((SampleActivity) getActivity()).onButtonClickedListener ();
}
if (onButtonClickedListener != null) {
onButtonClickedListener
.onButtonClicked();
}
}
};
}
Fragment B:
public class FragmentB extends Fragment {
private OnButtonClickedListener onButtonClickedListener = new OnButtonClickedListener() {
#Override
public void onButtonClicked() {
Toast.makeText(getActivity(), "Button clicked", Toast.LENGTH_SHORT).show();
}
};
#Override
public void onResume() {
super.onResume();
SampleActivity sampleActivity = (SampleActivity) getActivity();
sampleActivity.setSearchBoxTextChangedListener(onButtonClickedListener);
}
}
Hope can help someone.
Setting the onClick attribute for a button in your layout, even your fragment's layout, will call the appropriate method on your Activity.
Your app can then send this signal from your Activity to fragment B.