Search code examples
androidkotlinretrofitbottomnavigationview

Data is not loading in HomeFragment after using different menu in BottomNavigationView in Android


I am fetching data from network and showing in my list. I am using BottomNavigationView in Main Screen. It shows 4 tabs. When i launch the app, data is loading in Home screen but when i go to some other tab in Bottom navigation view and comeback to home tab, Data is not loading. In Home Screen has view pager tabs.

MainActivity.kt

class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {

lateinit var tabs: TabLayout
lateinit var toolbar: Toolbar
lateinit var sharedPreferences: SharedPreferences

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    sharedPreferences = getSharedPreferences(AppConstants.PREF_NAME, Context.MODE_PRIVATE)

    toolbar = findViewById(R.id.toolbar)
    setSupportActionBar(toolbar)
    toolbar.setTitle(R.string.app_name)

    val navigationView1: BottomNavigationView = findViewById(R.id.nav_view)
    navigationView1.setOnNavigationItemSelectedListener(this)

    if (savedInstanceState == null) {
        loadFragment(MainFragment())
    }
}

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    var fragment: Fragment? = null

    when (item.itemId) {
        R.id.news -> {
            invalidateOptionsMenu()
            fragment = MainFragment()
        }

        R.id.source -> {
            fragment = SourcesFragment()
            toolbar.getMenu().clear()
            toolbar.setTitle("News Sources")
        }

        R.id.save -> {
            toolbar.setTitle("Saved Articles")
            toolbar.getMenu().clear()
            fragment = WatchListFragment()
        }

        R.id.settings -> {
            toolbar.setTitle("Settings")
            toolbar.getMenu().clear()
            fragment = SettingsFragment()
        }
    }

    loadFragment(fragment)
    return true
}

private fun loadFragment(fragment: Fragment?) {
    val transaction = supportFragmentManager.beginTransaction()
        .setCustomAnimations(R.anim.design_bottom_sheet_slide_in, R.anim.design_bottom_sheet_slide_out)
    transaction.replace(R.id.container, fragment!!)
    transaction.commit()
}

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.main, menu)
    return true
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {
    when (item?.itemId) {
        R.id.action_search -> {
            startActivity(Intent(this, SearchActivity::class.java))
        }
        else -> ""
    }
    return true
}

}

MainFragment.kt

class MainFragment : Fragment() { lateinit var tabs: TabLayout lateinit var pager: ViewPager lateinit var adapter: PagerAdapter

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    var view = inflater.inflate(R.layout.fragment_main, container, false)

    pager = view.findViewById(R.id.viewpager)
    setupViewPager(pager)

    pager.addOnPageChangeListener(onPageChangeListener)

    tabs = view.findViewById(R.id.tabs)
    tabs.setupWithViewPager(pager)
    Log.d("LIVE", "onCreateView")
    return view
}

private fun setupViewPager(pager: ViewPager) {
    adapter = PagerAdapter(fragmentManager!!)
    adapter.addFragment(TopNewsFragment(), "Top News")
    adapter.addFragment(TechnologyFragment(), "Technology")
    adapter.addFragment(BusinessFragment(), "Business")
    adapter.addFragment(SportsFragment(), "Sports")
    adapter.addFragment(EntertainmentFragment(), "Entertainment")
    adapter.addFragment(ScienceFragment(), "Science")
    adapter.addFragment(HealthFragment(), "Health")
    pager.adapter = adapter
    adapter.notifyDataSetChanged()
}
private val onPageChangeListener = object : ViewPager.OnPageChangeListener {
    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
    }

    override fun onPageSelected(position: Int) {
        adapter.notifyDataSetChanged()
    }

    override fun onPageScrollStateChanged(state: Int) {
    }
}

}

fragment_main.xml

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabs"
            style="@style/Widget.MaterialComponents.TabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:elevation="10dp"
            app:tabGravity="center"
            app:tabIndicatorColor="@color/tab_selected_color"
            app:tabMode="scrollable"
            app:tabSelectedTextColor="@color/tab_selected_color"
            app:tabTextColor="@color/textColorPrimary" />

        <androidx.viewpager.widget.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    </LinearLayout>

</FrameLayout>

activity_main.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:elevation="10dp">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        app:elevation="4dp"
        app:itemIconTint="@drawable/bottom_navigation_text_color"
        app:itemTextColor="@drawable/bottom_navigation_text_color"
        app:labelVisibilityMode="labeled"
        app:menu="@menu/bottom_navigation_menu" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Home Screen

DataNotloading

Updated Code:

class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {

    lateinit var tabs: TabLayout
    lateinit var toolbar: Toolbar
    lateinit var sharedPreferences: SharedPreferences

    private val mNewsFragment = MainFragment()
    private val mSourceFragment: SourcesFragment = SourcesFragment()
    private val mSaveFragment: WatchListFragment = WatchListFragment()
    private val mSettingFragment = SettingsFragment()

    var activeFragment: Fragment= MainFragment()
    val fm: FragmentManager = supportFragmentManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sharedPreferences = getSharedPreferences(AppConstants.PREF_NAME, Context.MODE_PRIVATE)

        toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)
        toolbar.setTitle(R.string.app_name)

        val navigationView1: BottomNavigationView = findViewById(R.id.nav_view)
        navigationView1.setOnNavigationItemSelectedListener(this)

        fm.beginTransaction().add(R.id.container, activeFragment).commit();
        fm.beginTransaction().add(R.id.container, mSettingFragment).hide(mSettingFragment).commit();
        fm.beginTransaction().add(R.id.container, mSourceFragment).hide(mSourceFragment).commit();
        fm.beginTransaction().add(R.id.container, mSaveFragment).hide(mSaveFragment).commit();

/*        if (savedInstanceState == null) {
            val transaction = supportFragmentManager.beginTransaction()
                .setCustomAnimations(R.anim.design_bottom_sheet_slide_in, R.anim.design_bottom_sheet_slide_out)
            transaction.add(R.id.container, activeFragment).commit();
            transaction.add(R.id.container, activeFragment).hide(activeFragment).commit();
            transaction.add(R.id.container, activeFragment).hide(activeFragment).commit();
        }*/
    }

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
        var fragment: Fragment? = null

        when (item.itemId) {
            R.id.news -> {
                invalidateOptionsMenu()
                fragment = MainFragment()
                toolbar.getMenu().clear()
                toolbar.setTitle("News Headlines")
            }

            R.id.source -> {
                fragment = SourcesFragment()
                toolbar.getMenu().clear()
                toolbar.setTitle("News Sources")
            }

            R.id.save -> {
                toolbar.setTitle("Saved Articles")
                toolbar.getMenu().clear()
                fragment = WatchListFragment()
            }

            R.id.settings -> {
                toolbar.setTitle("Settings")
                toolbar.getMenu().clear()
                fragment = SettingsFragment()
            }
        }

        loadFragment(fragment)
        return true
    }

    private fun loadFragment(fragment: Fragment?) {
        val transaction = supportFragmentManager.beginTransaction()
            .setCustomAnimations(R.anim.design_bottom_sheet_slide_in, R.anim.design_bottom_sheet_slide_out).hide(activeFragment).show(fragment!!).commit();
        activeFragment = fragment;
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem?): Boolean {
        when (item?.itemId) {
            R.id.action_search -> {
                startActivity(Intent(this, SearchActivity::class.java))
            }
            else -> ""
        }
        return true
    }
}

Solution

  • You need to Add

    pager.setOffscreenPageLimit(2)
    

    After

    pager = view.findViewById(R.id.viewpager)
    

    For details https://developer.android.com/reference/android/support/v4/view/ViewPager#setoffscreenpagelimit

    UPDATE

    As per new findings, when you swipe between fragments, your fragment state is saved.It is saved because when you swipe, Viewpager comes into action. And when you set pager.setOffscreenPageLimit(2), 2 fragments on either side are saved.Hence you have no issues with swiping.

    But when you choose a fragment using BottomNavigationView, you are using replace. replace method removes a fragment from a container so onCreate() will get executed each time when user switches the tabs.

    Using the following code for BottomNavigationView, you can solve this issue.

    Bottom Line : Instead of Creating/replacing new fragments with BottomNavigationView, you can use hiding.

    MainActivity

    Declare a fragment variable like that

    Fragment activeFragment= new MainFragment();
    

    In onCreate, after setContentView, hide all fragments and commit them to the fragment manager, but do not hide the first fragment that will serve as home fragment.

      fm.beginTransaction().add(R.id.main_container,fragment1).commit();
      fm.beginTransaction().add(R.id.main_container, fragment2).hide(fragment2).commit();
      fm.beginTransaction().add(R.id.main_container, fragment3).hide(fragment3).commit();
    

    Replace your loadFragment() like that.

     private fun loadFragment(fragment: Fragment?) {
        val transaction = supportFragmentManager.beginTransaction()
            .setCustomAnimations(R.anim.design_bottom_sheet_slide_in, R.anim.design_bottom_sheet_slide_out).hide(activeFragment).show(fragment).commit();
        transaction.commit()
           activeFragment=fragment;
    }
    

    2ND UPDATE

    Replace

      fm.beginTransaction().add(R.id.main_container,fragment1).commit();
    

    With

      fm.beginTransaction().add(R.id.main_container,activeFragment).commit();