Dagger Android:可能的活动内存泄漏

时间:2018-01-11 05:03:17

标签: android dagger-2 dagger

我已经编写了一个示例应用来熟悉Dagger Android。我有两个活动,每个活动都有一个简单的片段,一个主活动,它有一个按钮来启动一个Details活动,它有一个刚完成活动的按钮。我看到的是,当我完成详细信息活动时,它仍然在内存中,每次单击按钮转到详细信息时,都会创建一个新实例(按预期方式),但在退出时不会释放。

我已经按如下方式定义了Dagger模块:

AppComponent:

@Component(modules = [AppModule::class,
    AndroidSupportInjectionModule::class,
    BuilderModule::class,
    StorageModule::class])
@ApplicationScope
interface AppComponent {
    @Component.Builder
    interface Builder {

        @BindsInstance
        fun application(application: DaggerSampleApp): Builder

        fun build(): AppComponent
    }

    fun inject(app: DaggerSampleApp)
}

的AppModule:

@Module(subcomponents = [MainActivitySubComponent::class,
    MainFragmentSubComponent::class,
    DetailActivitySubComponent::class,
    DetailFragmentSubComponent::class])
@ApplicationScope
class AppModule {

    @Provides
    @ApplicationScope
    fun provideContext(application: DaggerSampleApp): Context {
        return application.applicationContext
    }
}

BuilderModule:

@Module
@ApplicationScope
abstract class BuilderModule {
    @Binds
    @IntoMap
    @ActivityKey(MainActivity::class)
    abstract fun bindMainActivityInjectorFactory(builder: MainActivitySubComponent.Builder): AndroidInjector.Factory<out Activity>

    @Binds
    @IntoMap
    @FragmentKey(MainFragment::class)
    internal abstract fun bindMainFragmentInjectorFactory(builder: MainFragmentSubComponent.Builder): AndroidInjector.Factory<out Fragment>

    @Binds
    @IntoMap
    @ActivityKey(DetailActivity::class)
    abstract fun bindDetailActivityInjectorFactory(builder: DetailActivitySubComponent.Builder): AndroidInjector.Factory<out Activity>

    @Binds
    @IntoMap
    @FragmentKey(DetailFragment::class)
    internal abstract fun bindDetailFragmentInjectorFactory(builder: DetailFragmentSubComponent.Builder): AndroidInjector.Factory<out Fragment>
}

详细信息活动组件:

@ActivityScope
@Subcomponent(modules = [DetailActivityModule::class, BitmapCacheModule::class])
interface DetailActivitySubComponent : AndroidInjector<DetailActivity> {
    @Subcomponent.Builder
    abstract class Builder : AndroidInjector.Builder<DetailActivity>()
}

详细信息片段组件:

@ActivityScope
@Subcomponent(modules = [DetailFragmentModule::class, BitmapCacheModule::class])
interface DetailFragmentSubComponent : AndroidInjector<DetailFragment> {
    @Subcomponent.Builder
    abstract class Builder : AndroidInjector.Builder<DetailFragment>()
}

详情活动:

class DetailActivity : AppCompatActivity(), HasSupportFragmentInjector {
    @Inject
    lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>

    @Inject
    lateinit var appContext: Context

    @Inject
    lateinit var prefs: Prefs

    @Inject
    lateinit var bitmapCache: BitmapCache

    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detail)
        if (savedInstanceState == null) {
            supportFragmentManager
                    .beginTransaction()
                    .replace(R.id.container, DetailFragment.newInstance(), DetailFragment.FRAGMENT_TAG)
                    .commit()
        }

    }

    override fun supportFragmentInjector(): AndroidInjector<Fragment> {
        return fragmentDispatchingAndroidInjector
    }
}

详细信息片段:

class DetailFragment : Fragment() {

    @Inject
    lateinit var appContext: Context

    @Inject
    lateinit var prefs: Prefs

    @Inject
    lateinit var bitmapCache: BitmapCache

    override fun onAttach(context: Context?) {
        AndroidSupportInjection.inject(this)
        super.onAttach(context)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        return inflater.inflate(R.layout.fragment_detail, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById<Button>(R.id.button).setOnClickListener {
            activity?.finish()
        }
    }

    companion object {
        const val FRAGMENT_TAG = "main_fragment"

        fun newInstance() = DetailFragment()
    }
}

那么为什么没有公布详情活动?

enter image description here

1 个答案:

答案 0 :(得分:0)

经过多挖掘后,事实证明没有泄漏,我不确定为什么内存分析器显示3个分配而没有解除分配。

为了测试没有泄漏我覆盖了DetailsActivity中的finalize方法并添加了一个日志到控制台 - 当我从内存分析器触发GC时,在离开Details活动后,我看到日志正在打印,所以活动正在被垃圾收集。

我将不得不花一些时间来弄清楚详细信息活动的探查器输出以更好地理解它,但至少内存泄漏被证明是错误的。