4

I have this android fragment:

class MainFragment: BaseFragment(){

private val recyclerView by lazy { find<RecyclerView>(R.id.recyclerView) }
private val fab by lazy { find<FloatingActionButton>(R.id.fab) }

private val myLayoutManager by lazy { LinearLayoutManager(ctx, LinearLayoutManager.VERTICAL, false) }
private val myAdapter by lazy { MainCardAdapter(ctx, ArrayList<MainCardAdapterItem>(), R.layout.card_main_item) }

override val fragmentLayout = R.layout.fragment_main_layout

val DUMMY_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing"

)

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = super.onCreateView(inflater, container, savedInstanceState)
    setHasOptionsMenu(true)
    return view
}

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    Log.i("TAG", "onViewCreated")
    super.onViewCreated(view, savedInstanceState)
    (act as MainActivity).run { showWidgetStars(true) }

    recyclerView
            .linkToLayoutManager(myLayoutManager)
            .linkToAdapter(myAdapter)
            .addItemDecorator(removedSwipeLeftDecorator)
            .setOnItemChangedDuration(500)

    myAdapter.run {
        setAdapterItems(dummyList)
    }
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    inflater.inflate(R.menu.activity_main_context, menu)
    menu.findItem(R.id.action_secundary_menu).run {
        isVisible = true
        icon.setTintCompat(ctx, act.colorFromRes(R.color.appGreyDark))
    }
    super.onCreateOptionsMenu(menu, inflater)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    when(item.itemId){
        R.id.action_secundary_menu -> {
            act.showSnackBar("Clicked Secondary Menu!")
            return true
        }
        else -> return super.onOptionsItemSelected(item)
    }
  }
}                               

Everything works good except after i come back to this fragment (replaced in fragment manager by another, added to the backstack). When i return, i get an error saying: E/RecyclerView: No adapter attached; skipping layout. My bet is that its something to do with lazy properties but i can't figure it why. The fragment shows good on first run, only when going back it shows no recycler view items and display this message

johnny_crq
  • 4,291
  • 5
  • 39
  • 64
  • Can you check if `onViewCreated()` is run when you go back to the fragment? – AndroidEx Mar 02 '16 at 13:57
  • yes it does call it. – johnny_crq Mar 02 '16 at 14:57
  • Can you try setting your adapterItems in onResume instead? – CaseyB Mar 02 '16 at 15:05
  • idk why but it looks like views are not being saved automatically. I settled null to the adapter and layout manager in ondestroyview and it works. – johnny_crq Mar 02 '16 at 16:04
  • got it. the lazy initiation of the views will point to the old layout that was destroyed. – johnny_crq Mar 02 '16 at 16:08
  • can you provide me a basic example? – johnny_crq Mar 02 '16 at 18:29
  • What I suggest you do to avoid this, is use the kotlin android extensions plugin. It is easier to use (no more findById) and you avoid such problems. You can find the usage here: https://kotlinlang.org/docs/tutorials/android-plugin.html – maxandron Mar 02 '16 at 18:30
  • If you do try the approach of being lazy, but doing the resettable delegate when needed (as you ask for in another StackOverflow post), you can implement a resettable lazy delegate as shown here: http://stackoverflow.com/a/35757638/3679676 – Jayson Minard Mar 02 '16 at 21:02

1 Answers1

3

So as my properties are declared as lazy { find<View>(R.id.xxx} that basically means they will only be inflated from the layout one time. If the fragment's view somehow needs to be created again, the recyclerview property will point to an old view.

I'm not sure how a null pointer exception in that case was not thrown. Simply change the lazy to a var, and re-assign it on onCreateView. Another thing, if we want to use the same LayoutManager for the new inflated recyclerview, we must clear it from the previous recyclerview recyclerView.layoutManager = null, otherwise, an exception will be thrown saying that that layoutManager is already binded to another recyclerView.

johnny_crq
  • 4,291
  • 5
  • 39
  • 64
  • 1
    no NullPointer because they was initialized. after coming back from stack it's the same fragment instance, only view recreated. but lazy properties, as you pointed out, was not re-inited. since they.. you know, lazy and by definition should not. – vigilancer Mar 05 '16 at 01:39