代码之家  ›  专栏  ›  技术社区  ›  Wai Yan Hein

当使用TabLayout/ViewPager共享同一片段类设置时,片段中的Android Kotlin recycler视图未加载正确的数据

  •  0
  • Wai Yan Hein  · 技术社区  · 5 年前

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

    enter image description here

    每个选项卡都将共享同一个片段类,其中包含一个回收器视图。将根据通过包传递给片段的参数加载回收器视图的数据。

    这是我的寻呼机适配器类,在活动中用视图寻呼机设置

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

    如您所见,我对每个选项卡使用相同的片段,但将不同的变量传递到bundle中。

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

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

    如你所见,我的fragment类使用Rx observate和Rx observator。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)
        }
    }
    

    根据我的代码,每个选项卡下的每个recycler视图都应该加载相同的数据。但它并没有如预期的那样工作。这就是我得到的。

    当前选项卡

    此选项卡下没有数据加载到回收器视图中

    未来选项卡

    此选项卡下的回收器视图将加载两次数据:

    "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
    

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

    0 回复  |  直到 5 年前
        1
  •  1
  •   alaeri    5 年前

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

    在片段实现中:

    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
    }