I have a simple FragmentView in my app and 3 tabs. All 3 tabs have RecyclerView, the problem is first two tabs are not that complex, while third tab uses some complex operations and slows down the app making it lag while it's doing those operations. My question is: How can I prevent FragmentView to call onCreateView until it's focused?
Right now the third tab starts doing those operations when second tab is focused. I want it to start doing those methods when third tab is focused.
This is my code:
tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("Tab1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab2"));
tabLayout.addTab(tabLayout.newTab().setText("Tab3"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
viewPager = (ViewPager) findViewById(R.id.pager);
adapter = new PagerAdapter
(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
and this is my adapter:
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
RingtonesActivityFragment Ringtones = new RingtonesActivityFragment();
return Ringtones;
case 1:
FavoritesActivityFragment Favorites = new FavoritesActivityFragment();
return Favorites;
case 2:
MySongsActivityFragment Songs = new MySongsActivityFragment();
return Songs;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
and Tabs:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.main, container, false);
...
...
...
return rootView;
}
ViewPager will load 1 page to either side of the current page by default. Even if you set setOffscreenPageLimit to less than 1, it'll reset itself to 1. There is no getting around this unless you modify the ViewPager class to your liking.
To help with lazily executing code you can use ViewPager.OnPageChangeListener and its method onPageSelected(int position) to find out which tab is currently in focus. You can then postpone the work required once the Fragment is in focus.
I'd also add that if you're doing work which causes lag in your UI, you might want to consider moving the work to a background thread. If the work is layout related and you can't do it on a background thread use Hierarchy Viewer or Systrace to help you optimize.
Related
Following is my onCreate code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "Inside Base Drawer...");
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager){
#Override
public void onTabSelected(TabLayout.Tab tab){
tabPosition = tab.getPosition();
}
});
}
And following is my FragmentPageAdapter, for sliding tab layouts
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
Tab1Fragment tab1 = new Tab1Fragment();
return tab1;
case 1:
Tab1Fragment tab2 = new Tab2Fragment();
return tab2;
case 2:
Tab1Fragment tab3 = new Tab3Fragment();
return tab3;
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
}
Following is the tabFragment code:
public class Tab1Fragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState){
return inflater.inflate(R.layout.tab_activity_sheet_details_tab1, viewGroup, false);
}
}
I have a custom autocompleteTextView inside the tab layout (tab_activity_sheet_details_tab1)
Following is the code for the same:
<com.example.user.package.TabLayoutActivity.AutoCompleteAdapter.HistoryAutoCompleteTextView
android:id="#+id/history_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textCapCharacters"
android:imeOptions="flagNoExtractUi|actionSearch"/>
However, I'm not being able to access this element from TabLayoutActivity. What is the best way to access this after the fragment view is inflated?
And do note that there are similar items in all the three Tab Layouts.
Is there a need of a separate adapter holding all the three fragment layouts and access them? If so, from which lifecycle element can I access them?
P.S.: I'm looking for a non-adapter access to fragments, if possible (possibly by "layout id")?
Something like this would expose the view to the outside world:
public class Tab1Fragment extends Fragment {
View mView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState){
mView = inflater.inflate(R.layout.tab_activity_sheet_details_tab1, viewGroup, false);
return mView;
}
public HistoryAutoCompleteTextView getTextView() {
return (HistoryAutoCompleteTextView)mView.findViewById(R.id.history_text);
}
}
Then you can get it from the fragment:
textView = ((Tab1Fragment)fragment).getTextView()
But from a software design point of view, you should probably not do that and consider instead managing this view entirely in the Fragment and only expose the data collected.
i'm trying to create an Fragment with a tabs
first the main Activity has a bottom navigation with
4 fragments. 1 of the fragments i want to make a tabs which will insert another Fragment so basically the Fragment has a tabs with Fragment
and i have Class MyPagerAdapter here is the java file
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View pop = inflater.inflate(R.layout.fragment_adopt,
container, false);
TabLayout tabLayout = (TabLayout) pop.findViewById(R.id.tablayout);
tabLayout.addTab(tabLayout.newTab().setText("DOGS"));
tabLayout.addTab(tabLayout.newTab().setText("CATS"));
tabLayout.setTabGravity(tabLayout.GRAVITY_FILL);
final ViewPager viewpager = (ViewPager) pop.findViewById(R.id.pager);
final PagerAdapter adapter = new MyPagerAdapter.(getSupportFragmentManager().tablayout.getTabCount()) ;
ViewPager.setAdapter(adapter);
ViewPager.setOnPageListener(new tabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewpager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
return inflater.inflate(R.layout.fragment_adopt,container,false);
}
#Override
public void onFragmentInteraction(Uri uri) {
}
The problem is that the GetSupportFragment doesn't funtioning
thank you for answering and Godbles
The definition of getChildFragmentManager() is:
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
The definition of getSupportFragmentManager():
Return the FragmentManager for interacting with fragments associated with this fragment's activity.
I have implemented tab layout in android.I have 3 tabs-settings, clock, lost devices. While scrolling, the contents of tab get updated, but not the headings.But if I chose any tab heading, the content get displayed.
When I start the app, it shows 3 tabs. Suppose current highlighted tab is clock. When I scroll right, the contents of settings tab is displayed, but the current highlighted tab is still clock. It should be settings as per my need.
my code is
This is the main activity->
public class MainActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener{
//This is our tablayout
private TabLayout tabLayout;
//This is our viewPager
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Adding toolbar to the activity
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//Initializing the tablayout
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
//Adding the tabs using addTab() method
tabLayout.addTab(tabLayout.newTab().setText("clock"));
tabLayout.addTab(tabLayout.newTab().setText("settings"));
tabLayout.addTab(tabLayout.newTab().setText("lost devices"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
//Initializing viewPager
viewPager = (ViewPager) findViewById(R.id.pager);
//Creating our pager adapter
Pager adapter = new Pager(getSupportFragmentManager(), tabLayout.getTabCount());
//Adding adapter to pager
viewPager.setAdapter(adapter);
//Adding onTabSelectedListener to swipe views
tabLayout.setOnTabSelectedListener(this);
}
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
}
Pager->
public class Pager extends FragmentStatePagerAdapter {
//integer to count number of tabs
int tabCount;
//Constructor to the class
public Pager(FragmentManager fm, int tabCount) {
super(fm);
//Initializing tab count
this.tabCount= tabCount;
}
//Overriding method getItem
#Override
public Fragment getItem(int position) {
//Returning the current tabs
switch (position) {
case 0:
clock tab1 = new clock();
return tab1;
case 1:
settings tab2 = new settings();
return tab2;
case 2:
map tab3 = new map();
return tab3;
default:
return null;
}
}
//Overriden method getCount to get the number of tabs
#Override
public int getCount() {
return tabCount;
}
}
It is due to TabLayout and ViewPager is separate each other. You need to update their status in case of one of them make change. You have done with update ViewPager status when tab is selected. But vice versa you need to update Tablayout when ViewPager scroll.
Add listener for viewPager: viewPager.addOnPageChangeListener(this);. It will require you implement some methods.
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// don't use in that's case
}
#Override
public void onPageSelected(int position) {
// update Tablayout here
TabLayout.Tab tab = tabLayout.getTabAt(position);
if (tab != null) {
tab.select();
}
}
#Override
public void onPageScrollStateChanged(int state) {
// don't use in that's case
}
Don't forget to remove the listener if no longer use it
viewPager.removeOnPageChangeListener(this);
Hope it help !
you have setup your viewpager with tab layout. add this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
.....
......
....
//Adding adapter to pager
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
//Adding onTabSelectedListener to swipe views
tabLayout.setOnTabSelectedListener(this);
}
This question already has answers here:
ViewPager set current page programmatically
(3 answers)
Closed 4 years ago.
I have 3 tabs containing difference Fragments as:
Product and Services
Business Directory
Job
Bellow is my TabFragement Adapter The code is worked correctly but only 1 thing I want is:
=> I want to set Job Fragment as default in onCreate
This is my adapter.
public class TabFragment extends Fragment {
public static TabLayout tabLayout;
public static ViewPager viewPager;
public static int int_items = 3 ;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View x = inflater.inflate(R.layout.tab_layout,null);
tabLayout = (TabLayout) x.findViewById(R.id.tabs);
viewPager = (ViewPager) x.findViewById(R.id.viewpager);
viewPager.setAdapter(new MyAdapter(getChildFragmentManager()));
tabLayout.post(new Runnable() {
#Override
public void run() {
tabLayout.setupWithViewPager(viewPager);
}
});
return x;
}
class MyAdapter extends FragmentPagerAdapter{
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position)
{
switch (position){
case 0 : return new Product_Service();
case 1 : return new Business_Dir();
case 2 : return new Job();
}
return null;
}
#Override
public int getCount() {
return int_items;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0 :
return "Product & Srevices";
case 1 :
return "Business Directory";
case 2 :
return "Job";
}
return null;
}
}
}
You can use the fragment position index to show particular fragment as default using setCurrentItem method ofViewPager docs. Do this after setting adapter on viewpager
viewPager.setCurrentItem(2, false); // job fragment index is 2
false here mean , the transition to fragment 3 will be done instantly and if you pass true then chosen fragment will be displayed using scrolling effects ( you can use true when you want to give a little tour to user for first time)
I know this question has already been asked, more than once, but I think I'm looking for a different kind of "skip".
In a ViewPager linked with a TabLayout:
ViewPager vp = (ViewPager) findViewById(...);
TabLayout tl = (TabLayout) findViewById(...);
vp.setAdapter(new NoSwipePagerAdapter());
tl.setupWithViewPager(vp);
Since the viewpager is not scrollable, the expected behavior would be like: if tap on the "A" tab, viewpager scrolls to that tab.
My problem is that if I'm on "A" and I tap "D", the viewpager animate through B and C. What I'm trying to do is to literally "skip" B and C and show D.
Mainly for a matter of performance, since B and C are heavy fragments, but also for a matter of design.
I've tried every combination of setCurrentItem(int index, boolean smoothScroll), and it didn't work.
Is it possible to skip ViewPager pages? Thanks in advance.
if you want to skip two fragments and directly go to fourth fragment then write the following line
ViewPager.setCurrentItem(3);
I think, you should create PagerAdapter like bellow
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new Fragment_PatientList();
break;
case 1:
fragment = new FragmentB();
break;
case 2:
fragment = new FragmentC();
break;
default:
return null;
}
return fragment;
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
After creating pagerAdapter ,set viewPager.setAdapter(adapter)
At the end, you can connect tablayout with your viewpager like this
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}