Search code examples
androidandroid-studioandroid-fragmentsandroid-recyclerviewandroid-tablayout

Call method in Fragment from MainActivity


My application consists of a MainActivity that contains a TabLayout. The second tab has a RecyclerView which allows for items to be selected by clicking on them. The initial state is shown in the left figure. When one or more items are selected however, a overlaying Toolbar is shown with the options to (from left to right) copy, edit, delete or deselect the items. This situation is shown in the middle figure.

When for example the deselect option is chosen, the Toolbar should hide and the items should be deselected. The problem is that I do not know how to let the ListAdapter of the RecyclerView know that those items should be deselected. The current result of chosing the deselect option is shown in the right figure, so the Toolbar hides but the items do not get deselected.

enter image description here

The difficulty is that the RecyclerView is in the second fragment, called Fragment2, and the Toolbar with the options is part of the layout of the MainActivity. Fragment2 contains the method deselect. This method works fine, but am not able to call it from the MainActivity.

To solve this I have tried using an interface, but without success. The second way is as implemented in the code provided below. I am trying to call deselect in the onOptionsItemSelected method, but it tells me that fragment2 == null. I have also tried to do what Dimitar Darazhanski suggests, but I cannot figure out where to give fragment2 a tag and what container id to use in my case.

If you know how to solve this by modifying this approach or using an entirely different approach, please let me know!

MainActivity

import android.animation.Animator;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.os.Build;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    ViewPager mViewPager;
    TabLayout tabLayout;
    Integer currentTab, fragmentID;
    boolean itemsSelected;

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


        mViewPager = findViewById(R.id.viewpager_main_activity);
        tabLayout = findViewById(R.id.tablayout_main_activity);
        tabLayout.setupWithViewPager(mViewPager);
        itemsSelected = false;

        displayDefaultAppbar();
        handleFragments(mViewPager);
        currentTab = handleStartupFragment(mViewPager, savedInstanceState);
    }

    private void displayDefaultAppbar() {
        final Toolbar toolbar = findViewById(R.id.toolbar_main_activity);
        TabLayout tabLayout = findViewById(R.id.tablayout_main_activity);
        setSupportActionBar(toolbar);
        if (getSupportActionBar() != null) {
            getSupportActionBar().setTitle(getResources().getString(R.string.app_name));
        }
        toolbar.setVisibility(View.VISIBLE);
        tabLayout.setVisibility(View.VISIBLE);
    }

    private void handleFragments(ViewPager mViewPager) {
        SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mSectionsPagerAdapter);
        tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager) {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                super.onTabSelected(tab);
                int tabIconColor = ContextCompat.getColor(MainActivity.this, android.R.color.holo_red_dark);
                if(tab.getIcon() != null) {
                    tab.getIcon().setColorFilter(tabIconColor, PorterDuff.Mode.SRC_IN);
                }
                currentTab = tab.getPosition();
                handleToolbarOptions(currentTab);
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                super.onTabUnselected(tab);
                int tabIconColor = ContextCompat.getColor(MainActivity.this, android.R.color.black);
                if(tab.getIcon() != null) {
                    tab.getIcon().setColorFilter(tabIconColor, PorterDuff.Mode.SRC_IN);
                }
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                super.onTabReselected(tab);
            }
        });
    }

    private Integer handleStartupFragment(ViewPager mViewPager, Bundle savedInstanceState) {
        Intent intent = getIntent();
        Integer startupFragment;
        tabLayout.getTabAt(0).setText("1");
        tabLayout.getTabAt(1).setText("2");
        tabLayout.getTabAt(2).setText("3");
        if(intent.hasExtra("initialFragment")){
            Bundle bd = getIntent().getExtras();
            startupFragment = bd.getInt("initialFragment");
        } else {
            startupFragment = 1;
        }
        if (savedInstanceState == null) {
            mViewPager.setCurrentItem(startupFragment);
        }
        return startupFragment;
    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        fragmentID = fragment.getId();
    }

    private void handleToolbarOptions(Integer currentTab) {
        Toolbar toolbar = findViewById(R.id.toolbar_main_activity);
        if (currentTab == 1) {
            toolbar.getMenu().clear();
            toolbar.inflateMenu(R.menu.fragment2);
        } else {
            toolbar.getMenu().clear();
            toolbar.inflateMenu(R.menu.other);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Toolbar toolbar = findViewById(R.id.toolbar_main_activity_selected);
        if (toolbar.isShown()) {
            getMenuInflater().inflate(R.menu.selected, menu);
        } else if (currentTab == 1) {
            getMenuInflater().inflate(R.menu.fragment2, menu);
        } else {
            getMenuInflater().inflate(R.menu.other, menu);
        }
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.selected_close) {
            if (findViewById(R.id.toolbar_main_activity_selected) != null) {
                hideSelectedToolbar();
                Fragment2 fragment2 = (Fragment2) getSupportFragmentManager().findFragmentById(R.id.tablayout_main_activity);
                if(fragment2 == null) {
                    Toast.makeText(this,"null",Toast.LENGTH_SHORT).show();
                } else if (!fragment2.isAdded()) {
                    Toast.makeText(this,"Not added",Toast.LENGTH_SHORT).show();
                } else {
                    fragment2.deselect();
                }
            }
            return true;
        } else {
            return super.onOptionsItemSelected(item);
        }
    }

    public void displaySelectedToolbar() {
        final Toolbar toolbar = findViewById(R.id.toolbar_main_activity_selected);
        toolbar.setVisibility(View.VISIBLE);
        if (Build.VERSION.SDK_INT >= 21) {
            toolbar.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    Animator animator = ViewAnimationUtils.createCircularReveal(toolbar, toolbar.getWidth(), 0, 0,toolbar.getWidth());
                    animator.setDuration(ANIMATION_DURATION);
                    toolbar.removeOnLayoutChangeListener(this);
                    animator.start();
                }
            });
        }
        toolbar.setTitleTextColor(ContextCompat.getColor(MainActivity.this, android.R.color.black));
        setSupportActionBar(toolbar);
    }

    public void hideSelectedToolbar() {
        final Toolbar toolbar = findViewById(R.id.toolbar_main_activity_selected);
        if (Build.VERSION.SDK_INT >= 21) {
            Animator animator = ViewAnimationUtils.createCircularReveal(toolbar, toolbar.getWidth(), 0, toolbar.getWidth(), 0);
            animator.setDuration(ANIMATION_DURATION);
            animator.start();
            animator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animator) {

                }

                @Override
                public void onAnimationEnd(Animator animator) {
                    toolbar.setVisibility(View.GONE);
                    displayDefaultAppbar();
                }

                @Override
                public void onAnimationCancel(Animator animator) {

                }

                @Override
                public void onAnimationRepeat(Animator animator) {

                }
            });
        } else {
            toolbar.setVisibility(View.GONE);
            displayDefaultAppbar();
        }
    }

    private class SectionsPagerAdapter extends FragmentPagerAdapter {

        private SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return new Fragment1();
                case 1:
                    return new Fragment2();
                case 2:
                    return new Fragment3();
                default:
                    return null;
            }
        }

        @Override
        public int getCount() {
            return 3;
        }
    }
}

Fragment2

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import java.util.ArrayList;

public class Fragment2 extends Fragment {

    ListAdapter adapter;
    RecyclerView rv;
    ArrayList<TestItem> list;
    Integer selected, selectedOld;

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

        selected = 0;
        selectedOld = 0;

        list = new ArrayList<>();
        list.add(new TestItem("Item 1",false));
        list.add(new TestItem("Item 2",false));
        list.add(new TestItem("Item 3",false));
        list.add(new TestItem("Item 4",false));
        list.add(new TestItem("Item 5",false));
        list.add(new TestItem("Item 6",false));

        rv = rootView.findViewById(R.id.rv_fragment2);
        adapter = new ListAdapter(getActivity());
        rv.setAdapter(adapter);
        rv.setLayoutManager(new LinearLayoutManager(getActivity()));

        return rootView;
    }

    private void handleToolbar() {
        if (selected == 1 && selectedOld == 0) {
            if (getActivity() != null) {
                ((MainActivity) getActivity()).displaySelectedToolbar();
            }
        } else if (selected == 0 && selectedOld == 1) {
            if (getActivity() != null) {
                ((MainActivity) getActivity()).hideSelectedToolbar();
            }
        }
    }

    public void deselect() {
        for (int i=0; i<list.size(); i++) {
            list.get(i).setSelected(false);
        }
        adapter.notifyDataSetChanged();
        rv.setAdapter(adapter);
    }
}

activity_main.xml

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbarlayout_main_activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar_main_activity"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="scroll|enterAlways|snap"
            android:background="?attr/colorPrimary"
            android:visibility="visible"/>

        <android.support.design.widget.TabLayout
            android:id="@+id/tablayout_main_activity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager_main_activity"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar_main_activity_selected"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorAccent"
        android:translationZ="4dp"
        android:visibility="invisible"/>

</android.support.design.widget.CoordinatorLayout>

fragment2.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/root_fragment2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_fragment2"
        android:paddingTop="150dp"
        android:paddingBottom="10dp"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        android:splitMotionEvents="false"
        android:clipToPadding="false"/>

</LinearLayout>

Solution

  • One solution you can use is LocalBroadcastManager as you can see in this question.

    Fragment2

    private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // you will be notified here, you can do your stuff(deselect) here
                String message = intent.getStringExtra("my_message");
                Log.d("receiver_message", "my_message = " + message);
            }
        };
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment2, container, false);
    
            LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mMessageReceiver,
                    new IntentFilter("my_event_tag"));
    
            return rootView;
    
        }
    
        @Override
        public void onDestroy() {
            LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mMessageReceiver);
            super.onDestroy();
        }
    

    MainActivity

    private void callDeselectFromMainActivity() {
        Intent intent = new Intent("my_event_tag");
        intent.putExtra("my_message", "This is text should go to fragment...");
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }
    

    When you call callDeselectFromMainActivity method from MainActivity. It should call onReceive method in Fragment2.