【问题标题】: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_width="match_parent"
    android:orientation="vertical"
    android:id="@+id/fragment_container"
    android:layout_height="match_parent">


        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <com.google.android.material.tabs.TabLayout
                android:id="@+id/inbox_tab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                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_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="LinearLayoutManager"/>

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

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

问题

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

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

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

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()
}

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

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

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

我怎样才能做到这一点?

【问题讨论】:

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

标签: android android-fragments activity-lifecycle android-viewpager2 fragment-lifecycle


【解决方案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
猜你喜欢
  • 2012-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多