如何在销毁活动之前在视图寻呼机内的片段中执行某些操作

Posted

技术标签:

【中文标题】如何在销毁活动之前在视图寻呼机内的片段中执行某些操作【英文标题】:How to perform certain operations in a fragment inside a view pager before the activity is destroyed 【发布时间】:2021-12-29 01:33:16 【问题描述】:

我的活动布局如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_
    android:orientation="vertical"
    android:id="@+id/fragment_container"
    android:layout_>


        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager"
            android:layout_
            android:layout_>
            <com.google.android.material.tabs.TabLayout
                android:id="@+id/inbox_tab"
                android:layout_
                android:layout_
                style="@style/TabLayoutStyle"
                />
        </androidx.viewpager2.widget.ViewPager2>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

适配器如下所示

class InboxAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) 

    override fun getItemCount(): Int = 2

    override fun createFragment(position: Int): Fragment =
        InboxFragment().apply 
 
            arguments = Bundle().apply 
               // Our object is just an integer :-P
               putInt(InboxFragment.CURRENT_TAB, position)
            
        
    

片段布局由一个在onCreateView 方法中创建和初始化的回收器视图组成。

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_
        android:layout_
        app:layoutManager="LinearLayoutManager"/>

我的活动调用 API 端点以获取两组列表,表示已读和未读通知的组合,每一个都填充在特定片段的回收器视图中。

活动将值存储在两组实时数据实例中,并在two fragments like the tutorial suggests 之间传递数据。这很好用。

问题

我必须向后端发送一个 PUT 请求,其中请求正文包含当前在前台的片段的未读通知列表。

    当用户切换标签时 当用户离开屏幕时

对于第一个选项,我可以在我的片段中执行如下操作:

override fun onPause() 
    // Aggregates the list of unread notifications, and submits a PUT request.
    // Updates the view model live data backing list as well to mark as read.
    // View Model is initialised as per the tutorial

    inboxViewModel.markNotificationsAsRead(arguments?.getInt(CURRENT_TAB, -1) ?: 0)
    super.onPause()

当用户离开屏幕时,第二个用例会失败,从而破坏活动。在这种情况下,两个片段都会在它们的视图被销毁之前暂停。这会导致两个列表中的两个未读通知都被标记为已读。

考虑用户在第一个片段(默认加载)上的用例,然后离开收件箱屏幕导航到由另一个活动管理的另一个屏幕,然后我只希望显示未读通知第一个片段被标记为已读。

由于未加载第二个片段,因此不应将本应显示在第二个片段中的未读通知标记为已读。

我怎样才能做到这一点?

【问题讨论】:

为什么不在用户点击通知后立即将它们标记为已读? 我们也对点击进行此操作,但在这种特定情况下,我们希望在用户离开屏幕时将其标记为已读。 只是为了澄清这不是推送通知,而是类似电子邮件的收件箱屏幕。 【参考方案1】:

当片段可见时将消息标记为已读。所以在Activity销毁的时候不需要标记消息是否被读取。

或者在片段中添加一个公共字段来标记片段是否已显示。然后根据这个标签调用inboxViewModel.markNotificationsAsRead

How to determine if the fragment is displayed

------------------------------------20210-11-12------ ------------------ 演示代码sn-p

interface ICheckFragment 
    fun markShown()

    fun hasShown(): Boolean


// in your adapter
xxxAdapter: FragmentPagerAdapter(fm) 
    private val fragments = mutableListOf<Fragment>()
    init 
        val fragment = PlaceholderFragment.newInstance(1)
        val fragment2 = PlaceholderFragment.newInstance(2)
        fragments.add(fragment)
        fragments.add(fragment2)
    
    override fun getItem(position: Int): Fragment 
        return fragments[position]
    



// in your activity code
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener 
            // Please notice that this callback not be called at first when viewpager shown. 
            // You need mark fragment at position 0 shown manually 
            override fun onTabSelected(tab: TabLayout.Tab?) 
                val position = tab?.position ?: 0
                val fragment = sectionsPagerAdapter.getItem(position)
                if (fragment is ICheckFragment) 
                    fragment.markShown()
                
            

            override fun onTabUnselected(tab: TabLayout.Tab?) = Unit

            override fun onTabReselected(tab: TabLayout.Tab?) = Unit

        )
val fragment0 = sectionsPagerAdapter.getItem(0)
                if (fragment is ICheckFragment) 
                    fragment.markShown()
                

// in your fragment
class xxxFragment: Fragment(), ICheckFragment 
    ...
    private var hasShown = false
    override fun markShown() 
        hasShown = true
    

    override fun hasShown(): Boolean 
        return hasShown
    

    override fun onPause() 
        super.onPause()
        // do your logic
        if (hasShown) 

         else 

        
    


【讨论】:

两个原因:1. 无法区分新旧通知。 2. 建议的解决方案已在 AndroidX 片段中弃用。 developer.android.com/reference/androidx/fragment/app/… @Kartik 监控TabLayout的onTabSelected事件如何,然后设置是否显示Fragment 您介意粘贴代码 sn-p, @Kartik 我用演示代码 sn-p 更新了我的答案。 @leimenghao 你可以看看这个issue

以上是关于如何在销毁活动之前在视图寻呼机内的片段中执行某些操作的主要内容,如果未能解决你的问题,请参考以下文章

如何刷新其活动的 MenuitemSelected 上的片段?

由于休息api延迟,视图寻呼机中的第一个片段未显示

从活动更新视图页面中片段中的列表视图

如何防止在方向更改时重新创建片段寻呼机中的片段?

将活动回调发送到片段

片段的布局被活动的工具栏/标签布局覆盖