13

I have an Activity that contains a BottomNavigationView, and this bottomnav helps the activity to display three fragments. These fragments load well, and I use an AsyncTask to do every heavy operation, while in the UI thread, I show a ProgressBar until everything loads.
There is a weird behaviour with my fragment: The first time I load the fragment it takes some time to actually display it, instead of displaying it instantly with a progressbar.
This thing only happens the first time, and only in this fragment.
The fragment code only contains this:

@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        new LoadData(getView(), getContext()).execute();
    }

private class LoadData extends AsyncTask<Void, Void, Void> {

        private View v;
        private Context context;

        public LoadData(View v, Context context) {
            items = new ArrayList<>();
            this.v = v;
            this.context = context;
        }

        @Override
        protected Void doInBackground(Void... voids) {
            setItems(context); //Heavy operation
            adapter = new DashAdapter(items, context);
            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //shows progressbar
            progress = v.findViewById(R.id.DFProgress);
            progress.setVisibility(View.VISIBLE);
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            setPager();
            //sets viewPager and hides progressbar
            progress.setVisibility(View.GONE);
        }
    }

In the gif below, if you look at the bottomnavigationview at the bottom, you can see that it takes time to display the fragment. But after trying to load the fragment a second time, it loads as expected. enter image description here

How could I make the fragment to load the right way?

user229044
  • 232,980
  • 40
  • 330
  • 338
RushedPotato
  • 181
  • 2
  • 11

3 Answers3

6

I had the same problem. I have two options.

  1. Use postdelay when you call LoadData or
  2. First add all fragments with manually. You manage navigationItemSelected yourself.

Like this:

val firstFragment: Fragment = FirstFragment()
val secondFragment: Fragment = SecondFragment()
val thirdFragment: Fragment = ThirdFragment()

val navView: BottomNavigationView = findViewById(R.id.nav_view)

var active = firstFragment
fm.beginTransaction().add(R.id.nav_host_fragment, thirdFragment, "3").hide(thirdFragment).commit()
fm.beginTransaction().add(R.id.nav_host_fragment, secondFragment, "2").hide(secondFragment).commit()
fm.beginTransaction().add(R.id.nav_host_fragment, firstFragment, "1").commit()

navView.setOnNavigationItemReselectedListener {  }
navView.setOnNavigationItemSelectedListener { item ->
       when (item.itemId) {
           R.id.navigation_first -> {
               fm.beginTransaction().hide(active).show(firstFragment).commit()
               active = firstFragment

           }
           R.id.navigation_second -> {
               fm.beginTransaction().hide(active).show(secondFragment).commit()
               active = secondFragment
           }
           R.id.navigation_third -> {
               fm.beginTransaction().hide(active).show(thirdFragment).commit()
               active = thirdFragment
           }
       }
        true
   }

And remove these lines in your nav_host_fragment:

app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation"
Kasım Özdemir
  • 5,414
  • 3
  • 18
  • 35
0

When I tried @Kasım Özdemir 's answer, Each time the activity is launched, There was an initial ripple effect on the first item in bottom navigation view.(because I am using material bottom navigation view, which has a default ripple effect. And also UI was not visible when I tap for the first time, but I think that was because I was using different method than @Kasım Özdemir to change my active fragment when Item is clicked.

I didn't want to start my activity with first item, but with middle item in navigation view, which is "FragmentTwo" in below case. So the ripple effect was quite irrelevant.

So, I just attached the fragment instead of adding it and then hiding it, and now there is no ripple, Here is how code looks in Kotlin...

    val firstFragment: Fragment = FragmentOne()
    val middleFragment: Fragment = FragmentTwo()
    val thirdFragment: Fragment = FragmentThree()
    var fragment: Fragment? = null
    var bnv: BottomNavigationView? = null

    bnv = findViewById(R.id.bottom_navigation)
    bnv!!.selectedItemId = R.id.middle_page

  //fragments attached other than the fragment linked with middle item    
    supportFragmentManager.beginTransaction().attach(firstFragment).commit()
    supportFragmentManager.beginTransaction().attach(thirdFragment).commit()

    supportFragmentManager.beginTransaction().add(R.id.activity_main_container, middleFragment())
        .commit()
 bnv!!.setOnItemSelectedListener { item ->

            when (item.itemId) {    
                R.id.first_page -> fragment = firstFragment
                R.id.middle_page -> fragment = middleFragment
                R.id.third_page -> fragment = thirdFragment    
            }
    
            if (item.isChecked){
                false
            }

            else {
                supportFragmentManager.beginTransaction()
                    .setCustomAnimations(R.anim.fade_in, R.anim.fade_out).replace(
                        R.id.activity_main_container,
                        fragment!!
                    ).commit()
                true
            }
        }

So, using attach can also work fine instead of adding and then hiding it... for more information you can check this answer

(If you haven't already, Try using Navigation Component for bottom navigation, like this. It is more handy in some case, as it handles default backStack management by itself.)

Akhil Hothi
  • 67
  • 10
  • Please provide additional details in your answer. As it's currently written, it's hard to understand your solution. – Community Sep 06 '21 at 22:00
-1

you can use jetpack navigation for simple bottombar navigation

Simple Bottom Navigation with Jetpack Navigation:

Let’s start by including the Jetpack Navigation library in your apps by adding these lines in app’s build.gradle file:

def nav_version = "2.1.0"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

We start by creating a simple bottom navigation flow first. For that, you need to do first add NavHostFragment in your single activity layout file. Add this in the activity_main.xml file inside the FrameLayout tag.

<fragment
  android:id="@+id/fragNavHost"
  android:name="androidx.navigation.fragment.NavHostFragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:defaultNavHost="true"
  app:navGraph="@navigation/bottom_nav_graph" />

You will see an error saying “Cannot resolve symbol @navigation/bottom_nav_graph .”

    <?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bottom_nav_graph.xml"
    app:startDestination="@id/homeFragment2">

    <fragment
        android:id="@+id/homeFragment2"
        android:name="com.wajahatkarim3.bottomnavigationdemo.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" />

    <fragment
        android:id="@+id/searchFragment2"
        android:name="com.wajahatkarim3.bottomnavigationdemo.SearchFragment"
        android:label="fragment_search"
        tools:layout="@layout/fragment_search" />

    <fragment
        android:id="@+id/notificationsFragment2"
        android:name="com.wajahatkarim3.bottomnavigationdemo.NotificationsFragment"
        android:label="fragment_notifications"
        tools:layout="@layout/fragment_notifications" />

    <fragment
        android:id="@+id/profileFragment2"
        android:name="com.wajahatkarim3.bottomnavigationdemo.ProfileFragment"
        android:label="fragment_profile"
        tools:layout="@layout/fragment_profile" />
</navigation>

Its time for add some code in our activity class. Open MainActivity.kt file, and create a method setupViews() in it. Call this in onCreate() of the activity. Add these lines in the setupVeiws() method.

    fun setupViews()
{
    // Finding the Navigation Controller
    var navController = findNavController(R.id.fragNavHost)

    // Setting Navigation Controller with the BottomNavigationView
    bottomNavView.setupWithNavController(navController)

    // Setting Up ActionBar with Navigation Controller
    // Pass the IDs of top-level destinations in AppBarConfiguration
    var appBarConfiguration = AppBarConfiguration(
        topLevelDestinationIds = setOf (
            R.id.homeFragment,
            R.id.searchFragment,
            R.id.notificationsFragment,
            R.id.profileFragment
        )
    )
    setupActionBarWithNavController(navController, appBarConfiguration)
}