Reputation: 93
I am trying to make a module class AdaptersModules, which provides ViewPagerAdapter. ViewPagerAdapter is a class extending FragmentPagerAdapter. ViewPagerAdapter constructor requires FragmentManager.
My activity class is:
public class TabsActivity extends AppCompatActivity {
public FragmentManager fm = getSupportFragmentManager();
@Inject ViewPagerAdapter adapter;
@Inject HomeFragment homeFragment;
@Inject ChallengeFragment challengeFragment;
@Inject FriendsFragment friendsFragment;
@Inject OptionsFragment optionsFragment;
@Inject QuickPhotoFragment quickPhotoFragment;
@Inject TrophiesFragment trophiesFragment;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.tabsTabLayout) TabLayout tabLayout;
@BindView(R.id.tabsViewPager) ViewPager viewPager;
private int[] tabIcons = { R.drawable.ic_home,
R.drawable.ic_quick_photo,
R.drawable.ic_challenge,
R.drawable.ic_friends,
R.drawable.ic_trophies,
R.drawable.ic_settings };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
ButterKnife.bind(this);
((MeetBamApplication)getApplication())
.getComponent()
.inject(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
setupViewPager(viewPager);
tabLayout.setupWithViewPager(viewPager);
for (int i=0; i<viewPager.getAdapter().getCount(); i++)
tabLayout.getTabAt(i).setIcon(tabIcons[i]);
}
private void setupViewPager(ViewPager viewPager) {
adapter.addFragment(homeFragment);
adapter.addFragment(quickPhotoFragment);
adapter.addFragment(challengeFragment);
adapter.addFragment(friendsFragment);
adapter.addFragment(trophiesFragment);
adapter.addFragment(optionsFragment);
viewPager.setAdapter(adapter);
}
}
My module class:
@Module
public class AdaptersModules extends TabsActivity{
@Singleton
@Provides
protected ViewPagerAdapter provideViewPagerAdapter(){
return new ViewPagerAdapter(fm);
}
}
And component:
@Singleton
@Component(modules = {
AppModule.class,
TabsModules.class,
AdaptersModules.class})
public interface ApplicationComponent {
void inject(MeetBamApplication meetBamApplication);
void inject(TabsActivity activity);
}
ViewPagerAdapter class is:
public class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
public void addFragment(Fragment fragment){ mFragmentList.add(fragment);}
public ViewPagerAdapter(FragmentManager fm) { super(fm); }
@Override
public Fragment getItem(int position) { return mFragmentList.get(position); }
@Override
public int getCount() { return mFragmentList.size(); }
}
When I run and test app I get:
FATAL EXCEPTION: main
Process: com.thomsoncompany.meetbamgo, PID: 23733
java.lang.IllegalStateException: Activity has been destroyed
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1515)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:638)
at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:621)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:139)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1177)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)
at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1545)
at android.view.View.measure(View.java:17782)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5625)
at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:668)
at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:735)
at android.view.View.measure(View.java:17782)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5625)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:459)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
at android.view.View.measure(View.java:17782)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5625)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1692)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:760)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:629)
at android.view.View.measure(View.java:17782)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5625)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:459)
at android.view.View.measure(View.java:17782)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5625)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1692)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:760)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:629)
at android.view.View.measure(View.java:17782)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5625)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:459)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2644)
at android.view.View.measure(View.java:17782)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2389)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1399)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1623)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1277)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6483)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:802)
at android.view.Choreographer.doCallbacks(Choreographer.java:605)
at android.view.Choreographer.doFrame(Choreographer.java:574)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:788)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5549)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
What should I do?
Upvotes: 5
Views: 2816
Reputation: 21447
When you are using Dagger 2 in Android you need to be very careful to make sure that your injected members track the lifecycles of the injection targets correctly.
ViewPagerAdapter depends on a FragmentManager. FragmentManager
is not an application singleton. A single FragmentManager will become available to an Activity
some time after onCreate()
and will follow the lifecycle of that Activity only. In other words, when that Activity is destroyed then the FragmentManager
is unavailable for use. If you retain a reference to it afterwards by making it a singleton then you will get a memory leak and the above error because the Activity with which it is associated will no longer exist.
The correct way to handle this is to make a new component that tracks the lifecycle of your Activity:
@PerActivity
@Component( dependencies = { ApplicationComponent.class }, modules = { TabsModule.class, AdaptersModule.class, TabActivityModule.class }
public interface TabComponent {
void inject(TabsActivtiy activity);
}
Then create a module for your Activity that can provide the members that need to track the lifecycle of that Activity:
@Module
public class TabActivityModule {
private final TabActivity activity;
public TabActivityModule(TabActivity activity) {
this.activity = activity;
}
@Provides
@PerActivity
FragmentManager fragmentManager() {
return activity.getFragmentManager();
}
}
Upvotes: 4