使用共享相同片段类的TabLayout / ViewPager进行设置时,片段中的Android Kotlin回收程序视图未加载正确的数据

时间:2019-10-24 22:24:00

标签: android android-recyclerview android-viewpager android-tablayout

我正在使用Kotlin开发一个Android应用程序。我正在建立一个TabLayout,每个标签处理一个片段。这是布局

enter image description here

每个选项卡将共享其中具有回收器视图的相同Fragment类。回收站视图的数据将根据通过捆绑包传递给片段的参数加载。

这是我的寻呼机适配器类,将与活动中的视图寻呼机一起设置

class EventListPagerAdapter (fragmentManager: FragmentManager): FragmentPagerAdapter(fragmentManager)
{
    var fragments: ArrayList<Fragment> = ArrayList<Fragment>()

    init {

        var currentFragment: Fragment = EventListFragment()
        var currentBundle: Bundle = Bundle()
        currentBundle.putInt(EventListFragment.KEY_TYPE, ApplicationController.EVENT_TYPE_CURRENT)
        currentFragment.arguments = currentBundle
        this.fragments.add(currentFragment)

        var futureFragment: Fragment = EventListFragment()
        var futureBundle: Bundle = Bundle()
        futureBundle.putInt(EventListFragment.KEY_TYPE, ApplicationController.EVENT_TYPE_FUTURE)
        futureFragment.arguments = futureBundle
        this.fragments.add(futureFragment)

        var pastFragment: Fragment = EventListFragment()
        var pastBundle: Bundle = Bundle()
        pastBundle.putInt(EventListFragment.KEY_TYPE, ApplicationController.EVENT_TYPE_PAST)
        pastFragment.arguments = pastBundle
        this.fragments.add(pastFragment)
    }

    override fun getItem(position: Int): Fragment {
        return this.fragments.get(position)
    }

    override fun getCount(): Int {
        return this.fragments.size
    }

    override fun getPageTitle(position: Int): CharSequence? {
        when (position) {
            0 -> return ApplicationController.instance.getString(R.string.event_list_tab_current)
            1 -> return ApplicationController.instance.getString(R.string.event_list_tab_future)
        }

        return ApplicationController.instance.getString(R.string.event_list_tab_past)
    }
}

如您所见,我为每个选项卡使用相同的片段,但将不同的变量传递给包。

这是带有回收器视图实现的片段类

class EventListFragment: Fragment()
{
    @Inject
    lateinit var eventService: IEventService
    lateinit var eventList: ArrayList<EventModel>
    lateinit var eventListAdapter: EventListAdapter
    var eventType: Int? = 0
    val TAG = "EVENT_LIST_FRAGMENT"

    companion object{
        val KEY_TYPE = "key_type"
        lateinit var eventListObservable: Observable<List<EventModel>>
        lateinit var eventListObserver: Observer<List<EventModel>>
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_event_list, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        this.initialise()

        super.onViewCreated(view, savedInstanceState)
    }

    private fun initialise() {
        ApplicationController.instance.appComponent.inject(this)
        eventType = arguments?.getInt(KEY_TYPE, 0)
        Log.i(TAG, "event type is $eventType")

        //initialising the RxKotlin observable and observer
        eventListObservable = Observable.empty()
        eventListObserver = setUpEventListObserver()
        eventListObservable.subscribe(eventListObserver)

        //initialising the event list recycler view
        eventList = ArrayList<EventModel>()
        event_list_rc_list.layoutManager = GridLayoutManager(activity, 1)
        eventListAdapter = EventListAdapter(eventList)
        event_list_rc_list.adapter = eventListAdapter
        eventService.getEvents(eventType as Int)
    }

    private fun setUpEventListObserver(): Observer<List<EventModel>> {
        return object : Observer<List<EventModel>> {
            override fun onSubscribe(d: Disposable) {

            }

            override fun onNext(t: List<EventModel>) {
                eventList.addAll(t)
                eventListAdapter.notifyDataSetChanged()
            }

            override fun onError(e: Throwable) {

            }

            override fun onComplete() {

            }
        }
    }
}

您可以看到我的片段类正在使用Rx可观察者和Rx观察者。 eventService属性负责为回收者视图加载数据。现在,我正在使用该类的伪造版本来加载数据,并通过Rx观察器将数据发送回片段。

class FakeEventService: IEventService
{
    override fun getEvents(eventType: Int) {
        Handler().postDelayed({
            EventListFragment.eventListObserver.onNext(listOf(
                EventModel(11, "Event 1"),
                EventModel(12, "Event 2"),
                EventModel(13, "Event 3"),
                EventModel(14, "Event 4"),
                EventModel(15, "Event 5"),
                EventModel(16, "Event 6"),
                EventModel(17, "Event 7")
            ))
        }, 1000)
    }
}

根据我的代码,每个标签下的每个回收者视图都应加载相同的数据。但是它没有按预期工作。这是我得到的。

当前标签

此标签下的“回收者”视图中未加载任何数据

“未来”标签

此标签下的回收站视图正在两次加载数据:

"Event 1"
"Event 2"
"Event 3"
"Event 4"
"Event 5"
"Event 6"
"Event 7"
"Event 1"
"Event 2"
"Event 3"
"Event 4"
"Event 5"
"Event 6"
"Event 7"

过去的标签

此选项卡下的回收者视图已加载正确的数据。 (此功能正在按预期运行)

以下是事件类型的值

val EVENT_TYPE_CURRENT: Int = 1
val EVENT_TYPE_FUTURE: Int = 2
val EVENT_TYPE_PAST: Int = 3

我的代码有什么问题?为什么第一个选项卡不加载任何数据,为什么第二个选项卡加载两次数据?

1 个答案:

答案 0 :(得分:1)

在片段适配器中的IIRC,实例化当前位置的片段和下一个片段,一个接一个。

在您的片段实现中:

lateinit var eventListObservable: Observable<List<EventModel>>
lateinit var eventListObserver: Observer<List<EventModel>>

包含在伴随对象中。它们链接到类而不是实例。

创建将来的片段时,它将设置可观察对象,这将覆盖当前片段实例的值。

我的建议:

class FakeEventService: IEventService{

    private val observableCurrent = Observable.just(listOf(
                EventModel(11, "Event Current 1"),
                EventModel(12, "Event Current 2"),
                EventModel(13, "Event ... 3"),
                EventModel(14, "Event 4"),
                EventModel(15, "Event 5"),
                EventModel(16, "Event 6"),
                EventModel(17, "Event 7")
            ).delay(1, TimeUnit.SECOND)
   )

   private val observableFuture = Observable.just(listOf(
                EventModel(11, "Event Future 1"),
                EventModel(12, "Event Future 2"),
                EventModel(13, "Event Future 3"),
                EventModel(14, "Event ... 4"),
                EventModel(15, "Event 5"),
                EventModel(16, "Event 6"),
                EventModel(17, "Event 7")
            ).delay(1, TimeUnit.SECOND)
  )


   override fun getEvents(eventType: Int): Observable<List<EventModel>> {
        return when(eventType){
           EventType.CURRENT -> observableCurrent
           EventType.FUTURE -> observableFuture
   }

}

然后在您的片段中,您可以删除可观察的代码并执行

var disposableSubscription: Disposable? = null

override fun onStart(){
    super.onStart()
    //Please add an onError listener if the call could fail.
    disposableSubscription = eventService.getEvents(eventType).subscribe{ events ->
        eventList.addAll(t)
        eventListAdapter.notifyDataSetChanged()
    }
}

override onStop(){
   super.onStop()
   disposableSubscription?.dispose()
   disposableSubscription = null
}