user1660595
user1660595

Reputation:

How to set up listeners nicely between fragments?

I have an app with 4 tabs, all are Fragments and have an adapter because I'm using RecyclerView. On the first tab I have items. I want the second tab to show the items that are checked on the first and listen to the changes. The 3rd tab shows the items from the 2nd tab (=1st tab checked items) when I click on a button on the first segment. Now I set the listeners in onCreate and onCreateView. Sometimes it's working, sometimes not. My suspicion is that the create methods aren't executed in the same order every time. The other problem is that sometimes my Fragment has to notify the listener, sometimes the the Fragment's adapter. How do I treat it nicely?

First tab (it's adapter will notify)

public class EventFragment extends Fragment implements BettingEventAdapter.BettingItemClickListener {

    private RecyclerView recyclerView;
    static private BettingEventAdapter adapter;
    private BettingListDatabase database;
    private static Answer bettingData = null;
    private static final String TAG = "EVENT";
    private static BettingEventAdapter.BettingItemClickListener listener;

    public static void setListener(BettingEventAdapter.BettingItemClickListener _listener) {
        listener = _listener;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        database = BettingListDatabase.getInstance(this.getContext());

        loadBettingData();

    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_events,
                container, false);

        recyclerView = view.findViewById(R.id.MainRecyclerView);
        adapter = new BettingEventAdapter(this);
        adapter.addBettingItemListener(listener);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getBaseContext()));
        recyclerView.setAdapter(adapter);

        loadItemsInBackground();

        return view;
    }

Second tab:

public class TicketFragment extends Fragment implements BettingEventAdapter.BettingItemClickListener {

    private RecyclerView recyclerView;
    TextView prizeTextView;
    EditText stakeInput;
    Button bSave;

    private static BettingTicketAdapter.TicketSaveClickListener listener;
    private BettingListDatabase database;
    private BettingTicketAdapter adapter;
    double odds=1;
    int stake=0;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        database = BettingListDatabase.getInstance(this.getContext());
        EventFragment.setListener(this);
            }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_ticket,
                container, false);

        recyclerView = view.findViewById(R.id.TicketRecyclerView);
        adapter = new BettingTicketAdapter();
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getBaseContext()));
        recyclerView.setAdapter(adapter);
}

Third tab:

public class TicketListFragment extends Fragment implements BettingTicketAdapter.TicketSaveClickListener {

    private BettingTicketListAdapter parentAdapter;
    private BettingListDatabase database;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        database = BettingListDatabase.getInstance(this.getContext());
        TicketFragment.setListener(this);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        super.onCreateView(inflater, container, savedInstanceState);

        View view = inflater.inflate(R.layout.fragment_ticket_list,
                container, false);
        RecyclerView parentRecyclerView = view.findViewById(R.id.SavedTicketParentRecyclerView);
        parentAdapter = new BettingTicketListAdapter();
       //TODO db-ből feltölteni
        loadItemsInBackground();
        parentRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getBaseContext()));
        parentRecyclerView.setAdapter(parentAdapter);

        return view;
    }

Pager activity:

public class PagerActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pager);
    }

    @Override
    protected void onResume() {
        super.onResume();
        ViewPager mainViewPager = findViewById(R.id.mainViewPager);
        TabPagerAdapter tabPagerAdapter = new TabPagerAdapter(getSupportFragmentManager(), this);
        mainViewPager.setAdapter(tabPagerAdapter);
    }
}

Upvotes: 1

Views: 64

Answers (1)

G. Ciardini
G. Ciardini

Reputation: 1307

https://developer.android.com/training/basics/fragments/communicating

To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.

Here is an example for your Fragment:

EventFragment

public class EventFragment extends Fragment {
    OnEventSelectedListener callback;

    public void setOnEventSelectedListener(OnEventSelectedListener callback) {
        this.callback = callback;
    }

    // This interface can be implemented by the Activity, parent Fragment,
    // or a separate test implementation.
    public interface OnEventSelectedListener {
        public void onEventSelected(int position);
    }

    // ...
}

PagerActivity

    public class PagerActivity extends AppCompatActivity implements EventFragment.OnEventSelectedListener{

    // ...

    // In order to receive event callbacks from the fragment, the activity that
    // hosts it must implement the interface defined in the fragment class.
    //For example, the following activity implements the interface from the above example.

    public void onEventSelected(int position) {
        // ...
    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        if (fragment instanceof EventFragment) {
            EventFragment eventFragment = (EventFragment) fragment;
            eventFragment.setOnEventSelectedListener(this);
        }
    }
}

For example, the following method in the fragment is called when the user clicks on a list item. The fragment uses the callback interface to deliver the event to the parent activity.

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    // Send the event to the host activity
    callback.onEventSelected(position);
}

Upvotes: 2

Related Questions