david96develop
david96develop

Reputation: 145

Communication between Activity to multiple fragments in android

I am making a history activity that implements fragments with a For cycle into a linear layout.

In that history activity, I have a horizontal scrollbar that when I click a view it returns the index of the view. Then I send it by a listener to a fragment, but the problem is that I have multiple fragments, and only one fragment is getting the response. I want all of the fragments to receive the call. How do I fix this?

This is the for that I have in my history activity:

OnCustomEventListener mListener;
View.OnClickListener myClickListener = new OnClickListener(){
    @Override
    public void onClick(View v) {
    // here is where I get the index of the scroll bar
    indexChild = ((ViewGroup) uno.getParent()).indexOfChild(v);

    // here is where I call the method of the interface
    mListener.onEvent(indexChild);
}};

// here is where i set the fragments to the linear layout
for(i = 0; i<cant;i++){
    if(Utils.History_Thread == false) {
        final Fragment Frag = new PlaceholderFragment();
        Bundle bundle = new Bundle();
        bundle.putInt("dispositivo", dev);
        bundle.putInt("row",i);
        Frag.setArguments(bundle);
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, Frag).commit();
        try {
                sleep(150);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    } else {
        break;
    }
}

This is the fragment:

public class PlaceholderFragment extends org.holoeverywhere.app.Fragment
        implements ScrollViewListener,OnCustomEventListener {
    private static LinearLayout padre;
    OnHeadlineSelectedListener mCallback;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            more.. implementations

            // here is when i implement the listener of mListener of History Activ.
            ((History)activity).mListener = this;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " implement headlistener);                      
        }
    }


    // here I override the method and set the background color of the view I want

    @Override
    public void onEvent(int index) { 
        padre.getChildAt(index).setBackgroundColor(Color.GREEN);
    }
}

Only one of the fragments is being called, so only that fragment's view is painted.

interface

public interface OnCustomEventListener{
    public void onEvent(int index);
}

Here is a picture of what is happening:

enter image description here

I want all to be painted with green.

Actually the last fragment of the for is painted, maybe this help.

Upvotes: 1

Views: 1040

Answers (2)

snowdragon
snowdragon

Reputation: 753

I usually like to use a library like greenrobot's EventBus. It really makes communication between different components very clean, and also makes it easier dealing with background/UI threads. It saves a lot of repetitive code and interfaces and also tested by the community using it.

Example:

// sender (activity or other)
EventBus.getDefault().post(new ClickEvent(index));

// receiver (fragments, or other)
EventBus.getDefault().register(this); // in onCreate()
EventBus.getDefault().unregister(this); // in onDestroy()
public void onEvent(ClickEvent clickEvent) { ... }

Slide with additional info: http://www.slideshare.net/greenrobot/eventbus-for-android-15314813

Upvotes: 0

indivisible
indivisible

Reputation: 5012

Firstly, please format your code correctly. It's a mess and very difficult to read right now.

Also, you've got getSupportFragmentManager().beginTransaction().add(R.id.container, Frag).commit(); inside your for loop. You are performing a completely new transaction for every fragment addition. Are you sure that's how you want to do it?

You could be doing something more like:

FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction();
for (...) {
    ....
    fragTrans.add(...);
}
fragTrans.commit();

But as for your question:

You could send the message (call onEvent()) for each Fragment manually but then you'd have to keep track of every one you use. Not so difficult with only a few but if you start to use many then I guess it could get hard to follow before too long.

What I might do is collect all the Fragments into a collection and iterate over them inside that. Use a few Interfaces to make sure everything has the right methods and a reminder to the Fragments to register themselves if they should.


Interface for Activity

public interface MyActivityInterface
{
    public void registerOnEventListener(MyFragmentInterface myFragment);
    public void triggerEvent(int index);
}

Interface for Fragment

public interface MyFragmentInterface
{
    public void onEvent(int index);
    public void registerSelf();
}

Activity

public class MyActivity
        extends Activity
        implements MyActivityInterface
{
    private OnEventListenerCollection eventListeners;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        //...
        eventListeners = new OnEventListenerCollection();
    }

    @Override
    public void registerOnEventListener(MyFragmentInterface myFragment)
    {
        eventListeners.add(myFragment);
    }

    @Override
    public void triggerEvent(int index)
    {
        eventListeners.invokeOnEvents(index);
    }
}

Fragment

public class MyFragment
        extends Fragment
        implements MyFragmentInterface
{
    private MyActivityInterface myActivity;

    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);
        try
        {
            myActivity = (MyActivityInterface) activity;
        }
        catch (ClassCastException e)
        {
            Log.e("TAG", "Parent Activity must implement MyActivityInterface");
            throw e;
        }
        registerSelf();
    }

    @Override
    public void onEvent(int index)
    {
        // do whatever it is you wanted to trigger
    }

    @Override
    public void registerSelf()
    {
        myActivity.registerOnEventListener(this);
    }
}

Class to hold your registered Fragments and trigger the 'onEvents'

public class OnEventListenerCollection
{
    private List<MyFragmentInterface> myFragments;

    public OnEventListenerCollection()
    {
        myFragments = new ArrayList<MyFragmentInterface>();
    }

    public void add(MyFragmentInterface fragment)
    {
        myFragments.add(fragment);
    }

    public void invokeOnEvents(int index)
    {
        for (MyFragmentInterface fragment : myFragments)
        {
            fragment.onEvent(index);
        }
    }
}

Upvotes: 1

Related Questions