片段在方向改变时失去了听众

时间:2019-07-14 14:11:29

标签: android fragment

我正在使用片段进行活动。为了从片段到活动进行通信,我使用接口。这是简化的代码:

活动:

class HomeActivity : AppCompatActivity(), DiaryFragment.IAddEntryClickedListener, DiaryFragment.IDeleteClickedListener {

    override fun onAddEntryClicked() {
        //DO something
    }

    override fun onEntryDeleteClicked(isDeleteSet: Boolean) {
        //Do something
    }

    private val diaryFragment: DiaryFragment = DiaryFragment()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        diaryFragment.setOnEntryClickedListener(this)
        diaryFragment.setOnDeleteClickedListener(this)

        supportFragmentManager.beginTransaction().replace(R.id.content_frame, diaryFragment)
    }
}

片段:

class DiaryFragment: Fragment() {

    private var onEntryClickedListener: IAddEntryClickedListener? = null
    private var onDeleteClickedListener: IDeleteClickedListener? = null


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view: View = inflater.inflate(R.layout.fragment_diary, container, false)

        //Some user interaction
        onDeleteClickedListener!!.onEntryDeleteClicked()
        onDeleteClickedListener!!.onEntryDeleteClicked()

        return view
    }

    interface IAddEntryClickedListener {
        fun onAddEntryClicked()
    }

    interface IDeleteClickedListener {
        fun onEntryDeleteClicked()
    }

    fun setOnEntryClickedListener(listener: IAddEntryClickedListener) {
        onEntryClickedListener = listener
    }

    fun setOnDeleteClickedListener(listener: IDeleteClickedListener) {
        onDeleteClickedListener = listener
    }
}

这有效,但是当片段处于​​活动状态并且方向从纵向更改为横向或以其他方式更改时,侦听器为null。我无法将它们放到savedInstanceState,还是可以以某种方式?还是有解决该问题的另一种方法?

2 个答案:

答案 0 :(得分:1)

您的问题:

当您切换方向时,系统会为您保存并恢复片段的状态。但是,您没有在代码中说明这一点,实际上您最终得到了该片段的两个(!!)实例-一个实例由系统还原(不包含侦听器),而另一个实例由您自己创建。当您观察到该片段的侦听器为空时,这是因为为您还原的实例尚未重置其侦听器。

解决方案

首先,阅读the docs on how you should structure your code。 然后将您的代码更新为以下内容:

class HomeActivity : AppCompatActivity(), DiaryFragment.IAddEntryClickedListener, DiaryFragment.IDeleteClickedListener {

    override fun onAddEntryClicked() {
        //DO something
    }

    override fun onEntryDeleteClicked(isDeleteSet: Boolean) {
        //Do something
    }

    // DO NOT create new instance - only if starting from scratch
    private lateinit val diaryFragment: DiaryFragment

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        // Null state bundle means fresh activity - create the fragment
        if (savedInstanceState == null) {
            diaryFragment = DiaryFragment()
            supportFragmentManager.beginTransaction().replace(R.id.content_frame, diaryFragment)
        }
        else { // We are being restarted from state - the system will have
               // restored the fragment for us, just find the reference
            diaryFragment = supportFragmentManager().findFragment(R.id.content_frame)
        }

        // Now you can access the ONE fragment and set the listener on it
        diaryFragment.setOnEntryClickedListener(this)
        diaryFragment.setOnDeleteClickedListener(this)        
    }
}

希望有帮助!

答案 1 :(得分:0)

无需重写代码的简短答案是必须在活动履历表上还原侦听器,并且当您发现活动失去重点时,您应该“删除”它们。活动视图被完全破坏,并在旋转时重新绘制,因此自然不会在全新对象上发生任何事件。

旋转时,将在发生其他任何事情之前调用“ onDestroy”。重建时,将调用“ onCreate”。 (请参见https://developer.android.com/guide/topics/resources/runtime-changes) 这样做的原因之一是没有任何强迫您旋转后甚至使用相同布局的东西。可能会有不同的控件。 您真正需要做的就是确保在OnCreate中分配了事件挂钩。 有关oncreate中事件分配的示例,请参见此问题的答案。 onSaveInstanceState not working