
我有一个使用VIEwPager显示片段的应用程序的问题.一切正常,直到应用程序进入后台并被 *** 作系统杀死.似乎在恢复后我有2个IncIDentScreenFragment来处理事件,一个有一个空的演示者(MVP)使我的应用程序崩溃.
我的HomeActivity看起来像:
overrIDe fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentVIEw(R.layout.activity_main) presenter.onVIEwCreated() initVIEws(savedInstanceState) } private fun initVIEws(savedInstanceState: Bundle?){ mapVIEw.onCreate(savedInstanceState) mapVIEw.getMapAsync(this) initFragment() initMenu() } private fun initFragment(){ homeFragment = HomeScreenFragment.newInstance() incIDentFragment = IncIDentScreenFragment.newInstance() chatFragment = ChatFragment.newInstance() weatherFragment = WeatherFragment.newInstance() vIEwPager.adapter = VIEwPagerAdapter(supportFragmentManager, this) vIEwPager.offscreenPagelimit = 4 vIEwPager?.addOnPagechangelistener(object : VIEwPager.OnPagechangelistener { overrIDe fun onPageScrollStateChanged(state: Int) {} overrIDe fun onPageScrolled(position: Int, positionOffset: float, positionOffsetPixels: Int) {} overrIDe fun onPageSelected(position: Int) {bottom_navigation.currentItem = position} }) } overrIDe fun getFragmentByPos(pos: Int): Fragment { return when(pos){ 0 -> homeFragment 1 -> incIDentFragment 2 -> chatFragment 3 -> weatherFragment else -> { homeFragment } } }我的适配器:
class VIEwPagerAdapter internal constructor(fm: FragmentManager, activity:infinite_software.intelligence_center.intelligencecenter.ui.home.FragmentManager) : FragmentPagerAdapter(fm) { private val COUNT = 4 private val activity = activity overrIDe fun getItem(position: Int): Fragment{ var fragment: Fragment? = null when (position) { 0 -> fragment = activity.getFragmentByPos(0) 1 -> fragment = activity.getFragmentByPos(1) 2 -> fragment = activity.getFragmentByPos(2) 3 -> fragment = activity.getFragmentByPos(3) } return fragment!! } overrIDe fun destroyItem(container: VIEwGroup, position: Int, `object`: Any) { super.destroyItem(container, position, `object`) } overrIDe fun getCount(): Int { return COUNT } overrIDe fun getPageTitle(position: Int): CharSequence? { return "Section " + (position + 1) }}每个Fragment都有一个返回new Fragment的静态方法:
companion object { fun newInstance(): HomeScreenFragment { return HomeScreenFragment() } }当应用程序在后台被杀死时,我发现有两个对象(Fragment)可以监听事件,一个用Presenter正确实例化,一个没有.
在我的抽象BaseFragment类下面:
abstract class BaseFragment<P : BasePresenter<BaseVIEw>> : BaseVIEw,Fragment() { protected lateinit var presenter: P overrIDe fun getContext(): Context { return activity as Context } overrIDe fun onCreateVIEw(inflater: LayoutInflater, container: VIEwGroup?, savedInstanceState: Bundle?): VIEw? { return super.onCreateVIEw(inflater, container, savedInstanceState) } overrIDe fun onVIEwCreated(vIEw: VIEw, savedInstanceState: Bundle?) { super.onVIEwCreated(vIEw, savedInstanceState) presenter = instantiatePresenter() } overrIDe fun showError(error: String) { (activity as BaseActivity<BasePresenter<BaseVIEw>>).showError(error) } overrIDe fun showError(errorResID: Int) { (activity as BaseActivity<BasePresenter<BaseVIEw>>).showError(errorResID) } abstract fun onBackpressed(): Boolean /** * Instantiates the presenter the Fragment is based on. */ protected abstract fun instantiatePresenter(): P abstract val TAG: String事件片段代码:
class IncIDentScreenFragment: BaseFragment<IncIDentScreenPresenter>(), BaseVIEw, IncIDentVIEw, AlertFilterListener, AlertItemClickListener, IncIDentDetailListener { var rvAdapter : IncIDentAdapter? = null var state : Int = List_STATE overrIDe fun instantiatePresenter(): IncIDentScreenPresenter { return IncIDentScreenPresenter(this) } overrIDe val TAG: String get() = "INCIDENT" overrIDe fun getContext(): Context { return activity as Context } overrIDe fun onCreateVIEw(inflater: LayoutInflater, container: VIEwGroup?, savedInstanceState: Bundle?): VIEw? { super.onCreateVIEw(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_incIDent, container, false) } overrIDe fun onVIEwCreated(vIEw: VIEw, savedInstanceState: Bundle?) { super.onVIEwCreated(vIEw, savedInstanceState) initVIEws() presenter.onVIEwCreated() initObserve() } private fun initVIEws(){ //Reclycler vIEw alertRV.layoutManager = linearlayoutmanager(context) rvAdapter = IncIDentAdapter(ArrayList(), context, this) alertRV.adapter = rvAdapter //Apply Listeners headerBox.setFilterListener(this) incIDentDetailVIEw.setListener(this) } overrIDe fun initObserve() { //Init observe presenter model val alertObserver = Observer<ArrayList<AlertModel>> { alerts -> Timber.d("Data received from Presenter [$alerts]") showAlertList(alerts) } presenter.filtereDalertList.observe(context as BaseActivity<BasePresenter<BaseVIEw>>,alertObserver) } overrIDe fun updateThisFilters(BoxState: Boolean, level: Int) { presenter.updatefilterList(BoxState,level) } fun showOnlyThisLevel(level:Int){ presenter.showOnlyThisLevel(level) headerBox.disableBoxExcept(level) } fun showAlertList(List: ArrayList<AlertModel>){ rvAdapter?.updateData(List) } overrIDe fun onItemClick(model: AlertModel) { presenter.loaDalertDetail(model) } overrIDe fun showAlertDetail(model: AlertModel) { incIDentDetailVIEw.setUpFromModel(model) WhiteWizard.slIDeleftEffect(incIDentDetailVIEw,incIDentListRootElement) state = DETAIL_STATE } overrIDe fun onbackFromDetailpressed() { WhiteWizard.slIDeRightEffect(incIDentListRootElement,incIDentDetailVIEw) state = List_STATE } overrIDe fun showLoader() { loaderIncIDent.visibility = VIEw.VISIBLE } overrIDe fun hIDeLoader() { loaderIncIDent.visibility = VIEw.INVISIBLE } overrIDe fun onBackpressed(): Boolean { when(state){ List_STATE -> return false DETAIL_STATE -> { onbackFromDetailpressed() return true } else -> return false } } fun newInstance(): IncIDentScreenFragment { return IncIDentScreenFragment() }}当我点击homePage中的按钮显示我得到的片段内容:
Process: XXXXXX, PID: 3192 kotlin.UninitializedPropertyAccessException: lateinit property presenter has not been initialized at infinite_software.intelligence_center.intelligencecenter.base.BaseFragment.getPresenter(BaseFragment.kt:11) at XXXXXX.ui.home.incIDentScreen.IncIDentScreenFragment.showOnlyThisLevel(IncIDentScreenFragment.kt:78) at XXXXXX.ui.home.HomeActivity.filterDataWithSeverity(HomeActivity.kt:110) at XXXXXX.ui.home.homeScreen.HomeScreenFragment.filterBy(HomeScreenFragment.kt:76) at XXXXXX.ui.home.homeScreen.HomeScreenFragment$initVIEws.onClick(HomeScreenFragment.kt:56)如果我尝试打印片段的ID,我从方法调用showOnlyThisLevel()和onBackpressed()获得2个不同的ID.我想念的是什么?
解决方法:
在仔细搜索证据之后,我必须得出结论,问题源于FragmentPagerAdapter代表AndroID支持库作者的方法的错误,没有明确指出抽象方法getItem(int position)应该返回一个新的实例片段而不仅仅是“获取一个实例”.
当然,我们可以做一些关于错误名称的事情,因为它已经在野外停留了7年,但至少我们可以修复你的代码中源于此问题的错误;)
不用多说,你的NPE的原因是onCreateVIEw(实例化你的Presenter)永远不会被调用.
发生这种情况是因为您在此处创建片段:
overrIDe fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentVIEw(R.layout.activity_main) ... homeFragment = HomeScreenFragment.newInstance() incIDentFragment = IncIDentScreenFragment.newInstance()}您从FragmentPagerAdapter中的getItem(int position)内部返回此片段:
overrIDe fun getItem(position: Int): Fragment = when(position) { ... 1 -> activity.incIDentFragment ...}所以我们对activity.incIDentFragment的了解是,在它中,永远不会调用onCreateVIEw().
这是因为它从未真正添加到FragmentManager并且从未在屏幕上显示.
这是因为Activity中的super.onCreate(savedInstanceState)使用他们的no-args构造函数通过反射重新创建所有片段,同时保留它们的标记(请参阅findFragmentByTag).
正如你在this answer中看到的那样,或者我可以在这里引用:
// Do we already have this fragment? String name = makeFragmentname(container.getID(), itemID); Fragment fragment = mFragmentManager.findFragmentByTag(name); if (fragment != null) { if (DEBUG) Log.v(TAG, "Attaching item #" + itemID + ": f=" + fragment); mCurTransaction.attach(fragment); } else { fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + itemID + ": f=" + fragment); mCurTransaction.add(container.getID(), fragment, makeFragmentname(container.getID(), itemID));仅当FragmentPagerAdapter为片段设置的片段标记找不到片段时才调用getItem(position)方法,在低内存条件杀死应用程序后自动重新创建片段.
因此,您的新片段(您在Activity中手动创建)永远不会被使用,因此它没有视图,从未初始化,从未添加到FragmentManager,它与VIEwPager中的实际内容不同,并且在崩溃时崩溃你叫它.繁荣!
解决方案是在FragmentPagerAdapter的getItem(position)方法中实例化Fragment.要获取片段的实例,请使用this answer.
总结以上是内存溢出为你收集整理的android – 活动在后台被杀死后应用程序崩溃全部内容,希望文章能够帮你解决android – 活动在后台被杀死后应用程序崩溃所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)