android - 从另一个 fragment 返回到它后,带有 ViewPager 的 fragment 有空白页

标签 android android-fragments android-viewpager kotlin fragmentmanager

在我的应用程序中,我试图用 ViewPager 创建 2 个 fragment 。这些 fragment 有 3 个选项卡/页面,每个选项卡/页面都有 RecyclerView,它们应该由数据库支持,所以我将它们保存在 List 中。

class MainActivity : AppCompatActivity() {    
    val fragments = listOf(SwipeFragment(), SwipeFragment())

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

        supportFragmentManager.beginTransaction().replace(R.id.placeholder, fragments[0]).commit()
        button1.setOnClickListener { 
            supportFragmentManager.beginTransaction().replace(R.id.placeholder, fragments[0]).commit()
        }
        button2.setOnClickListener {
            supportFragmentManager.beginTransaction().replace(R.id.placeholder, fragments[1]).commit()
        }
    }
}

问题是离开 SwipeFragment 并返回后, View 似乎是空的。然后,如果您导航到例如最左边的页面,最右边的页面“出现”(当您转到它时)。 这导致中间页面保持空白。 (原因是 FragmentStatePagerAdapter 默认只保留当前页面和 2 个相邻页面。中间页面在具有 3 个选项卡的布局中不会刷新 - 我也尝试过使用 5 个选项卡和我可以通过来回将它们全部带回来)。

经过一些调试后,我发现代表页面的 fragment 没有从 FragmentManager 中删除,但主要的 SwipeFragment 是。即使阅读了几乎所有的源代码,我也无法理解 FragmentManager 的真正工作原理。

如果我能够以某种方式安全地从 FragmentManager 中删除 fragment ,它可能会起作用。
我已经尝试了一些保存状态的技术,但框架会自动执行(这实际上可能是导致此问题的原因)。
我只是 Android 的初学者,所以无论如何可能有更好的方法来做到这一点。我会将其余文件留在这里以供引用。


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.test.MainActivity">

    <FrameLayout
        android:id="@+id/placeholder"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0"
        android:orientation="horizontal">

        <Button
            android:id="@+id/button1"
            style="?android:buttonBarButtonStyle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="button1" />

        <Button
            android:id="@+id/button2"
            style="?android:buttonBarButtonStyle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="button2" />
    </LinearLayout>
</LinearLayout>

SwipeFragment.kt

class SwipeFragment : Fragment() {

    // TODO: set up and keep the database here

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

        val view = inflater!!.inflate(R.layout.fragment_swipe, container, false)
        view.tab_layout.setupWithViewPager(view.pager)
        view.pager.adapter = DummyPagerAdapter(activity.supportFragmentManager, index)

        return view
    }
}

fragment_swipe.xml

<android.support.v4.view.ViewPager 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.test.SwipeFragment">

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</android.support.v4.view.ViewPager>

ItemListFragment.kt

class ItemListFragment() : Fragment() {

    // Or keep the database here?
    // Probably not the best idea though

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

        val view = inflater!!.inflate(R.layout.fragment_item_list, container, false)
        if (view is RecyclerView) {
            view.layoutManager = LinearLayoutManager(view.context)
            view.adapter = MyItemRecyclerViewAdapter(DummyContent.ITEMS)
        }

        return view
    }
}

DummyPagerAdapter.kt

class DummyPagerAdapter(manager: FragmentManager, val parentIndex: Int) :
        FragmentStatePagerAdapter(manager) {

    override fun getItem(position: Int): Fragment = ItemListFragment()
    override fun getPageTitle(position: Int): CharSequence = "${ position + 1 }"
    override fun getCount(): Int = 3
}

以及Android Studio生成的RecyclerView.Adapter的基本实现

MyItemRecyclerViewAdapter.kt

class MyItemRecyclerViewAdapter(val values: List<DummyItem>) : 
        RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>() {
    ...
}

fragment_item_list.xml

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list"
    android:name="com.example.test.ItemListFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="LinearLayoutManager"
    tools:context="com.example.test.ItemListFragment"
    tools:listitem="@layout/fragment_item" />

最佳答案

您应该在 SwipeFragment 中使用 childFragmentManager 而不是 activity.supportFragmentManager

view.pager.adapter = DummyPagerAdapter(childFragmentManager, index)

讨论了 getSupportFragmentManager()getChildFragmentManager() 之间的区别 here .

Basically, the difference is that Fragment's now have their own internal FragmentManager that can handle Fragments. The child FragmentManager is the one that handles Fragments contained within only the Fragment that it was added to. The other FragmentManager is contained within the entire Activity.

关于android - 从另一个 fragment 返回到它后,带有 ViewPager 的 fragment 有空白页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47842191/

相关文章:

android - 新创建的布局文件未添加到 R.java

android - 图表引擎不连续线

java - 用于填充多个部分的 Android GridView 适配器

Android 库 Blurry 对我不起作用,模糊效果不适用

android - 如何在 ViewPager 中禁用特定页面滑动

android NumberPicker 样式与 eclipse 相同

java - 显示来自 run() 方法的对话框

android - DatePickerDialog 已将 androidx.fragment.app.DialogFragment 中的按钮涂黑

android - 带有 ViewPager 的 ActionBarSherlock 在进入和返回 backstack 时不调用 ViewPager fragment 生命周期方法

android - 如何在另一个 ViewPager2 中使用 ViewPager2