I have a ViewPager of fragments.
For each fragments, in the onCreateView(), I use AsyncTask to query the server.
I create the fragments in FragmentPagerAdapter's getItem().
However, because getItem() method will be called for the visible fragment and also the adjacent fragments, I am calling the onCreateView() and thus the AsyncTask of the adjacent Fragment even though the fragment is not visible.
How do I only call the AsyncTask of the visible fragment?
Is using onPageSelected() for the ViewPager the correct solution?
I used this method to call AsyncTask instead of in onCreateView() but then the onCreateView() of the fragment is not called.
Thank you.
You could override the method of Fragment:
setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint( isVisibleToUser);
if(isVisiableToUser) {
}
}
Related
I'm using navigation component and want to connect drawer layout with toolbar in each fragment, not the activity.
I tried this answer which is called on onViewCreated() but any view referenced from the activity is null. I guess it's because fragment is inflated in the layout before returning from the activity's onCreate method.
I use this extension function to connect the drawer with the fragment's toolbar, I tried to call it from onCreateView() and onViewCreated() but did't work and the activity's drawer layout is always null. I works only if it's called from onStart() but I don't think it's the right way:
private fun AppCompatActivity.setToolbar() {
setSupportActionBar(binding.toolbar)
setHasOptionsMenu(true)
val drawer = findViewById<DrawerLayout>(R.id.drawer)
binding.toolbar.setupWithNavController(findNavController(), drawer)
}
What's the right place to call this function?
When you call setContentView(R.id.activity_layout), the entire view hierarchy is first inflated, then attached to the Activity. It is only after setContentView() returns that findViewById() will find any of the newly inflated views.
When you use the <fragment> tag, the Fragment's view and the views of all of its child fragments are synchronously created as part of that inflation call. This means that setContentView() has not completed by the time the onCreateView() and onViewCreated() methods are called. This is why that calling findViewById() returns null - the activity's view hasn't actually finished being created.
FragmentContainerView was specifically built to avoid these special cases and instead use the same mechanisms as other fragments - namely, it just uses a normal FragmentTransaction to add your Fragment - the same as if you called beginTransaction()+commitNow() in your onCreate() method yourself. This means that the Fragment is not forced to synchronously create its view as part of setContentView(), but can do it alongside every other Fragment after setContentView() returns. This is what allows findViewById() from onCreateView() or onViewCreated() work.
You can achieve this by simply using an interface which you need to implement in activity. No need to reference activity's drawerLayout from fragment.
Interface like this:
interface DrawerWithToolbar {
fun setupToolbarDrawer(toolbar: MaterialToolbar)
}
Then in activity:
override fun setupToolbarDrawer(toolbar: MaterialToolbar) {
toolbar.setupWithNavController(navController,drawerLayout)
}
In fragment:
(activity as DrawerWithToolbar).setupToolbarDrawer(toolbar)
I'm using navigation component and want to connect drawer layout with toolbar in each fragment, not the activity.
I tried this answer which is called on onViewCreated() but any view referenced from the activity is null. I guess it's because fragment is inflated in the layout before returning from the activity's onCreate method.
I use this extension function to connect the drawer with the fragment's toolbar, I tried to call it from onCreateView() and onViewCreated() but did't work and the activity's drawer layout is always null. I works only if it's called from onStart() but I don't think it's the right way:
private fun AppCompatActivity.setToolbar() {
setSupportActionBar(binding.toolbar)
setHasOptionsMenu(true)
val drawer = findViewById<DrawerLayout>(R.id.drawer)
binding.toolbar.setupWithNavController(findNavController(), drawer)
}
What's the right place to call this function?
When you call setContentView(R.id.activity_layout), the entire view hierarchy is first inflated, then attached to the Activity. It is only after setContentView() returns that findViewById() will find any of the newly inflated views.
When you use the <fragment> tag, the Fragment's view and the views of all of its child fragments are synchronously created as part of that inflation call. This means that setContentView() has not completed by the time the onCreateView() and onViewCreated() methods are called. This is why that calling findViewById() returns null - the activity's view hasn't actually finished being created.
FragmentContainerView was specifically built to avoid these special cases and instead use the same mechanisms as other fragments - namely, it just uses a normal FragmentTransaction to add your Fragment - the same as if you called beginTransaction()+commitNow() in your onCreate() method yourself. This means that the Fragment is not forced to synchronously create its view as part of setContentView(), but can do it alongside every other Fragment after setContentView() returns. This is what allows findViewById() from onCreateView() or onViewCreated() work.
You can achieve this by simply using an interface which you need to implement in activity. No need to reference activity's drawerLayout from fragment.
Interface like this:
interface DrawerWithToolbar {
fun setupToolbarDrawer(toolbar: MaterialToolbar)
}
Then in activity:
override fun setupToolbarDrawer(toolbar: MaterialToolbar) {
toolbar.setupWithNavController(navController,drawerLayout)
}
In fragment:
(activity as DrawerWithToolbar).setupToolbarDrawer(toolbar)
I have a callback method I need to call once a fragment in my ViewPager is attached to my activity. In order to do this I'm overriding onAttachFragment(Fragment fragment) in the activity.
But I have 3 fragments in the ViewPager, so how can I check the fragment parameter in OnAttachFragment() to make sure it's the specific fragment I need?
If I am going about this wrong, I would like to know how to accomplish this the right way.
Figured it out! Instead of calling OnAttachFragment() in the activity, I'm calling the callback method in onActivityCreated() in the fragment where it needs to be called.
I have a RecyclerView in a Fragment which again is in a ViewPager, when I swipe between ViewPager pages, I see that onDetach of Fragment is being called but for some reason RecyclerView is still present in that particular position for the Fragment in ViewPager, even the scroll position of RecyclerView is being preserved when I come back to the detached Fragment.
I am using FragmentStatePagerAdapter for ViewPager and I am returning POSITION_NONE from getItemPosition() but it has no effect.
Please help me understand the problem here.
Try this points.
1) MyAdapter extends FragmentStatePagerAdapter
2) Set Adapter from fragment using getChildFragmentManager()
eg : mViewPager.setAdapter(new MyAdapter(getChildFragmentManager(), getActivity(), this))
3) From ViewpagerFrgment Override setUserVisibleHint method
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
//Update Recyclerview
} else {
}
}
it's because viewpager use a caching mecanism.
read this article :
http://doublenegative.com/fragment-state-restoration-and-the-fragmentstatepageradapter/
FragmentStatePagerAdapter saves the state and destroy the fragments; it also restores the state when fragments are recreated which restores the state of recycleview (the scrolling position).
From the end user it is the same behavior as using FragmentPageAdapter which keeps fragments in memory.
It's the normal and usually desired behavior.
I have a activity (Activity A) with a fragment that has a ListView inside of it and I'm calling another activity (Activity B) to add records to the fragment's list.
My problem is that calling adapter.notifyDataSetChanged on Activity A's onResume/onFragmentResume and the fragment's onResume changes nothing.
My adapter is populated in Activity A's onCreate.
I also tried inserting the adapter.notifyDataSetChanged in a runOnUiThread.
Any one tackled this situation before?
It is not a good suggestion but try to reinitialize the adapter and set it again and tell me if it is work fine.
You should populate your adapter in the fragment in either the onAttach(), or onViewCreated() methods. You could also populate it in the onCreate() of the fragment, then call notifyDataSetChanged in either of these lifecycle methods I suggest.
These methods will be called whenever the fragment is connected and drawn, thus, you can be sure that it will populate your Fragment correctly.
In general, have all your view related items (like adapter creation and population) in your fragment, and navigation (ActionBar, and flowing between Activities) in your Activity.