简体   繁体   中英

Navigation Drawer's Fragment Management

应用层次结构 I am developing an app where i am using only 1 Main Activity and Multiple fragment, Including ViewPager , Custom video/Image Gallery, Fullscreen Fragment(Without toolbar or bottom navigation button). I am not sure is it good practice or not but i am facing few issues cause of this.

Image above is actual App hierarchy. Following the issue i am facing.

  1. Toolbar doesn't change title of fragment, when press back button or going forward by clicking button or some link.
  2. Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment.
  3. Fragment State Loss when pressed back button or jumping directly to some fragment.
  4. Whether is it good practice to doing all task within Fragment with Single Activity .

I am also using single Toolbar whole app. Toolbar.xml

<android.support.v7.widget.Toolbar
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="@color/primary"
    app:contentInsetLeft="0dp"
    app:contentInsetStart="0dp"
    app:contentInsetStartWithNavigation="0dp"
    android:fitsSystemWindows="true"
    app:layout_collapseMode="pin"
    app:layout_scrollFlags="scroll|exitUntilCollapsed">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/toolbar_connections"
        android:visibility="visible"
        android:orientation="horizontal">
    <ImageView
        android:layout_width="35dp"
        android:layout_height="match_parent"
        android:id="@+id/appLogo"
        android:layout_gravity="center_vertical" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical|center_horizontal"
            android:textSize="22sp"
            android:id="@+id/activityTitle"
            android:textColor="@color/primary_text"
            />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/toolbar_chat"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"
        android:orientation="horizontal">

        <de.hdodenhof.circleimageview.CircleImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_vertical"
            android:layout_marginRight="5dp"
            android:src="@drawable/baby"
            android:id="@+id/User_Image_Toolbar"/>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:id="@+id/User_Name_Toolbar"
                android:textSize="17sp"
                android:textStyle="bold"
                android:layout_marginBottom="5dp"
                android:text="My Name"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Online"
                android:textStyle="italic"
                android:id="@+id/User_Online_Status_Toolbar"
                android:layout_marginBottom="5dp"
                android:layout_below="@+id/User_Name_Toolbar" />
        </LinearLayout>
    </LinearLayout>


</android.support.v7.widget.Toolbar>

Navigation Drawer (Single Activity which parent of all Fragments)

public class Navigation_Drawer extends AppCompatActivity implements UserData {

    Toolbar toolbar;
    DrawerLayout drawerLayout;
    NavigationView navigationView;
    String navTitles[];
    TypedArray navIcons;
    RecyclerView.Adapter recyclerViewAdapter;
    ActionBarDrawerToggle drawerToggle;
    public static final String TAG = "###Navigation Drawer###";
    boolean nextScreen;
    //Header
    ImageView headerImage,headerUserImage;
    TextView userName,userViews;
    Context context = this;
    //Setting Tabs
    ViewPager viewPager;
    TabAdapter tabAdapter;

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

        //Initialise Views
        drawerLayout = findViewById(R.id.Navigation_Drawer_Main);
        navigationView = findViewById(R.id.nvView);
        setupToolbar();
        navigationView.setItemIconTintList(null);
        setupDrawerContent(navigationView);
        settingHeaderItems();
        drawerToggle = setupDrawerToggle();
        getSupportActionBar().setHomeButtonEnabled(true);

        drawerLayout.addDrawerListener(drawerToggle);
        viewPager = findViewById(R.id.Navigation_Drawer_ViewPager);
        tabAdapter = new TabAdapter(getFragmentManager(), this, false);    


        viewPager.setAdapter(tabAdapter);

    }


    public void setupToolbar() {
        toolbar = findViewById(R.id.Navigation_Drawer_toolbar);
        setSupportActionBar(toolbar);
    }
    private ActionBarDrawerToggle setupDrawerToggle() {
        // NOTE: Make sure you pass in a valid toolbar reference.  ActionBarDrawToggle() does not require it
        // and will not render the hamburger icon without it.
        //return new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open,  R.string.drawer_close);
        return new ActionBarDrawerToggle(this, drawerLayout,toolbar, R.string.drawer_open,  R.string.drawer_close);
    }    


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        //  inflater.inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        //Handle Item Selection

        return super.onOptionsItemSelected(item);
    }
    private void setupDrawerContent(NavigationView navigationView) {
        navigationView.setNavigationItemSelectedListener(
                new NavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(MenuItem menuItem) {
                        selectDrawerItem(menuItem);
                        return true;

                    }

                });

    }





    public void ChangeFragment_ViewPager(int position, boolean outside) {
        if (outside) {
            Log.d(TAG, "Change Fragment Calling From Outside");
            tabAdapter = new TabAdapter(getFragmentManager(), this, false);
            viewPager.setAdapter(tabAdapter);
        }

        viewPager.setCurrentItem(position);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        showSystemUI();
        Log.d(TAG, "On Back Pressed");

    }

    public void showSystemUI() {
        if (getWindow() != null) {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getSupportActionBar().show();
        } else {
            return;
        }

    }


    public void selectDrawerItem(MenuItem menuItem) {
        // Create a new fragment and specify the fragment to show based on nav item clicked
        Fragment fragment = null;


        switch (menuItem.getItemId()) {

            case R.id.HeaderImageView:
                fragment = new EditProfile();
                break;
            case R.id.home_Fragment:
                Log.d(TAG,"Home Fragment Pressed ");
                getFragmentManager().popBackStack(null, android.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
                ChangeFragment_ViewPager(0,false);
                // Highlight the selected item has been done by NavigationView
                menuItem.setChecked(true);
                // Set action bar title
                setTitle(menuItem.getTitle());
                // Close the navigation drawer
                drawerLayout.closeDrawers();
                return;

            case R.id.ppl_Fragment:
                Log.d(TAG,"PPL Fragment Pressed ");
                ChangeFragment_ViewPager(1,false);
                // Highlight the selected item has been done by NavigationView
                menuItem.setChecked(true);
                // Set action bar title
                setTitle(menuItem.getTitle());
                // Close the navigation drawer
                drawerLayout.closeDrawers();
                return;

            case R.id.message_Fragment:
                Log.d(TAG,"Message Fragment Pressed ");
                fragment = new  Messages_Fragment();

                break;

            case R.id.addMedia_Fragment:
                Log.d(TAG,"Add Media Fragment Pressed ");
                fragment = new UserProfile_Photos();

                break;

            case R.id.invite_Fragment:
                Log.d(TAG,"Invite Fragment Pressed ");
                //fragmentClass = fragment_1.class;
                onInviteClicked();
                // Highlight the selected item has been done by NavigationView
                menuItem.setChecked(true);
                // Set action bar title
                setTitle(menuItem.getTitle());
                // Close the navigation drawer
                drawerLayout.closeDrawers();
                return;


            case R.id.setting_Fragment:
                Log.d(TAG,"Setting Fragment Pressed ");
                fragment = new  Setting_NavigationDrawer();

                break;

            case R.id.help_Fragment:
                Log.d(TAG,"Help Fragment Pressed ");
                //fragmentClass = fragment_1.class;
                fragment=new FullScreen_WebView();
                Bundle urlToSend=new Bundle();
                urlToSend.putString("webViewURL","http://boysjoys.com/test/Android/Data/help.php");
                //urlToSend.putString("webViewURL",chat_wrapper.getGoogleSearch().get(2));
                fragment.setArguments(urlToSend);
                FragmentTransaction transaction=((Activity)context).getFragmentManager().beginTransaction();
                //fragmentTrasaction.replace(R.id.Chat_Screen_Main_Layout,gallery);
                //transaction.replace(R.id.Chat_Screen_Main_Layout,fullScreen_webView);
                transaction.replace(R.id.Navigation_Main_Layout,fragment);
                transaction.addToBackStack(null);
                transaction.commit();

                // Highlight the selected item has been done by NavigationView
                menuItem.setChecked(true);
                // Set action bar title
                setTitle(menuItem.getTitle());
                // Close the navigation drawer
                drawerLayout.closeDrawers();
                return;

            case R.id.signOut_Fragment:
                new CheckLoginStatus(this, 0).execute();
                new Send_Session_Logout(this).execute();
                drawerLayout.closeDrawers();
                return;

        }


        FragmentTransaction fragmentTransaction=getFragmentManager().beginTransaction();
        fragmentTransaction.add(R.id.Navigation_Main_Layout, fragment);
        fragmentTransaction.setCustomAnimations(R.animator.enter_anim,R.animator.exit_anim);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();

        // Highlight the selected item has been done by NavigationView

        menuItem.setChecked(true);

        // Set action bar title

        setTitle(menuItem.getTitle());

        // Close the navigation drawer

        drawerLayout.closeDrawers();

    }
    private void settingHeaderItems(){
        View HeaderLayout = navigationView.inflateHeaderView(R.layout.navigation_header_image);
        //Main Screen Tabs With VIew Pager
        headerImage = HeaderLayout.findViewById(R.id.HeaderImageView);
        headerImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FragmentTransaction fragmentTransaction=getFragmentManager().beginTransaction();
                fragmentTransaction.replace(R.id.Navigation_Main_Layout, new EditProfile());
                fragmentTransaction.setCustomAnimations(R.animator.enter_anim,R.animator.exit_anim);
                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();
                drawerLayout.closeDrawers();
            }
        });
        headerUserImage = HeaderLayout.findViewById(R.id.HeaderProfilePicture);
        userName = HeaderLayout.findViewById(R.id.myImageViewText);
        userViews = HeaderLayout.findViewById(R.id.profileViews);
        if (Session.getUserCover().equals("Invalid Image")){
            headerImage.setBackgroundResource(R.drawable.cam_icon);
        }else {
            Log.d(TAG,"Path Of Cover Photo "+Session.getUserCover());
            Bitmap coverPhoto= BitmapFactory.decodeFile(Session.getUserCover());
            headerImage.setImageBitmap(coverPhoto);
            //  Glide.with(context).load(Session.getUserCover()).apply(new RequestOptions().skipMemoryCache(true).onlyRetrieveFromCache(false).diskCacheStrategy(DiskCacheStrategy.NONE)).into(holder.HeaderImage);
        }
        Bitmap bitmap = BitmapFactory.decodeFile(Session.getUserImage());

        userName.setText(Session.getUserFname()+" "+Session.getUserLname());
        headerUserImage.setImageBitmap(bitmap);
        if (Session.getProfileCounter().equals("0")){
            userViews.setText("No Profile VIsits");
        }
        else {
            userViews.setText("Profile views: "+ Session.getProfileCounter());
        }
    }

    @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }           
}

I tired alot to resolve this issue and after months of googling and stackoverflow im still stuck in same issue.

Issue example of Point 1:- When navigation drawer load first everything looks good, view pager changes title as per fragment. then if i click on Navigation Drawer's Menu which also open another fragment (For Ex: Recent Message). then title change successfully but when i press back button or trying to press home button which calls viewpager then title remain same as before ie Recent Message.

Setting Title in each fragment like this.

toolbar = (Toolbar) getActivity().findViewById(R.id.Navigation_Drawer_toolbar);
        ImageView appLogo = toolbar.findViewById(R.id.appLogo);
        TextView fragmentTitle = toolbar.findViewById(R.id.activityTitle);
        appLogo.setImageResource(DrawableImage);
        fragmentTitle.setText(Title);

Whether is it good practice to doing all task within Fragment with Single Activity.

It is a good practice to use fragments when you use with navigation drawers, tabs or bottom navigation.
Other than that, fragments are mostly preferred for reusable UI with different data.

You are doing all task within fragment with Single Activity because you are using navigation draw and tabs, so It is a good practice, I'd say.

Toolbar doesn't change title of fragment, when press back button or going forward by clicking button or some link.

You need to manually set the title for fragment whenever you are adding/replacing new fragment OR
on back press(backstack change), through Fragment only or using OnBackStackChangedListener as mentioned in docs .

You are just setting them while you are clicking through navigation items and not while clicking button or some link

Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment.

That too you'd need to handle manually. using onOptionItemSelected on click of android.R.id.home item. Like poping fragments out from stack.

The cause of your title persistence on back is setting title from Activity. ie using this setTitle(menuItem.getTitle()); instead set them through Fragment or if you are setting them trough Fragment remove from selectDrawerItem method.
Also at the end of selectDrawerItem method you are using fragmentTransaction.add instead use fragmentTransaction.replace

If application have to use Navigation Drawer which should be present in all views, then Fragment should be used. And its not a bad practice.

  1. Toolbar doesn't change title of fragment, when press back button or going forward by clicking button or some link.

Create a method in Base Activity

public void setFragmentTitle(String title){
        if(!TextUtils.isEmpty(title))
        mTitleText.setText(title);
    }

Access this method from your individual Fragments in onCreateView

((LandingActivity) getActivity()).setFragmentTitle(getActivity().getString(R.string.fragment_title));
  1. Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment.

    Use onOptionItemSelected on click of android.R.id.home , pop the current Fragment

  2. Fragment State Loss when pressed back button or jumping directly to some fragment

    You have to mention the values which needs to be persisted and repopulate it.


public class ActivityABC....{

private String mFName;
private TableSelectFragment mFragment;

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FragmentManager fm = getSupportFragmentManager();

    if (savedInstanceState != null) {

      mFragment=(TableSelectFragment)fm.getFragment(savedInstanceState,"TABLE_FRAGMENT");
      mFName = savedInstanceState.getString("FNAMETAG");

    }else{
      mFragment = new TableSelectFragment();
      fm.beginTransaction().add(R.id.content_frame,mFragment,"TABLE_FRAGMENT").commit();
       }
    }

   @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
       getSupportFragmentManager().putFragment(outState,"TABLE_FRAGMENT",mFragment);
    }
}

In your Fragment

TableSelectFragment{

  ....

   private String mFName;

   @Override
   public void onCreate(@Nullable Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setRetainInstance(true);
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        outState.putString("FNAMETAG", mFName);
        super.onSaveInstanceState(outState);
    }
}

EDIT 1: For Fragment Title not getting updated in BackButton press

While adding Fragment to backstack , do the following.

In your parent Activity

FragmentManager fragMan = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMan.beginTransaction();
LandingFrag landingFrag = LandingFrag.newInstance();
fragTrans.replace(R.id.landing_view, landingFrag,"LandingFrag");
fragTrans.addToBackStack(null);
fragTrans.commit();
landingFrag.setUserVisibleHint(true);

Now override onBackPressed in parent Activity

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {

            .. POP Fragment Backstack here

            Fragment fragment =  getActiveFragment();
            if(fragment instanceof  LandingFrag)
            {
                    LandingFrag landingFrag = (LandingFrag)fragment;
                    landingFrag.setUserVisibleHint(true);
            }

        }

  public Fragment getActiveFragment() {
        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
            return null;
        }
        Fragment fragment=null;
        int trackBackValue = 1;//INCREASE OR DECREASE ACCORDING TO YOUR BACK STACK

        try {
            fragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - trackBackValue);
        } catch (Exception e) {
        }
        return fragment;

   }

Now in LandingFrag

public class LandingFrag...
{

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setUserVisibleHint(false);
        .....
    }

    @Override
    public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
        super.onViewStateRestored(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
         ................    
          ((LandingActivity) getActivity()).setFragmentTitle("Current Fragment Title");
    }
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if(isVisibleToUser){
            try {
                ((LandingActivity) getActivity()).setFragmentTitle("Current Fragment Title");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM