Robert Vogl
Robert Vogl

Reputation: 250

Kotlin Errors After Converting from Java

I do not have very much experience with Kotlin, been doing most of my development in Java. I have converted my ArtistFragment to Kotlin in order to solve another issue. But after converting it I am getting to errors that I do not know how to resolve.

The first one is Smart cast to 'RecyclerView!' is impossible, because 'recyclerView' is a mutable property that could have been changed by this time and the second one is Cannot create an instance of an abstract class

I searched through Stackoverflow, but since I don't really understand the what the problem is I am not sure if they are relevant to my problems.

Here is my converted ArtistFragment:

class ArtistFragment : Fragment() {
    var spanCount = 3 // 2 columns
    var spacing = 20 // 20px
    var includeEdge = true
    private var recyclerView: RecyclerView? = null
    private var adapter: ArtistAdapter? = null
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_artist, container, false)
        recyclerView = view.findViewById(R.id.artistFragment)
        recyclerView.setLayoutManager(GridLayoutManager(activity, 3))
        LoadData().execute("")
        return view
    }

    abstract inner class LoadData : AsyncTask<String?, Void?, String>() {
        protected fun doInBackground(vararg strings: String): String {
            if (activity != null) {
                adapter = ArtistAdapter(activity, ArtistLoader().artistList(activity))
            }
            return "Executed"
        }

        override fun onPostExecute(s: String) {
            recyclerView!!.adapter = adapter
            if (activity != null) {
                recyclerView!!.addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, includeEdge))
            }
        }

        override fun onPreExecute() {
            super.onPreExecute()
        }
    }
}

I am seeing Smart cast to 'RecyclerView!' is impossible, because 'recyclerView' is a mutable property that could have been changed by this time here in this section: recyclerView.setLayoutManager(GridLayoutManager(activity, 3))

I am seeing Cannot create an instance of an abstract class here in this section LoadData().execute("")

I hoping someone can explain these error and how to fix them.

Thanks

Upvotes: 0

Views: 189

Answers (2)

cactustictacs
cactustictacs

Reputation: 19622

Smart cast to 'RecyclerView!' is impossible, because 'recyclerView' is a mutable property that could have been changed by this time is because recyclerView is a var. Kotlin has the concept of mutable (var) and immutable (val) variables, where a val is a fixed value, but a var can be reassigned.

So the issue is that recyclerView is a nullable type (RecyclerView?) and it could be null - so you need to make sure it's not null before you access it, right? findViewById returns a non-null RecyclerView, which gets assigned to recyclerView, so the compiler knows it can't be null.

But then it gets to the next line - what if the value of recyclerView has changed since the previous line? What if something has modified it, like on another thread? It's a var so that's possible, and the compiler can't make any guarantees about whether it's null or not anymore. So it can't "smart cast to RecyclerView!" (! denotes non-null) and let you just treat it as a non-null type in your code. You have to null check it again.

What Priyanka's code (recyclerView?.setLayoutManager(GridLayoutManager(activity, 3))) does is null-checks recyclerView, and only makes the call if it's non-null. Under the hood, it's copying recyclerView to a temporary val (which isn't going to change) and checks that, and then executes the call on that.

This is a pretty standard thing with Kotlin, and not just for nullable types - any var could possibly change at any moment, so it's typical to assign it to a temporary variable so you can do the stuff on that stable instance. Kotlin has a bunch of scope functions which are convenient for doing things on an object, and one of the benefits is that you know the reference you're acting on isn't going to change halfway through

Upvotes: 1

Priyanka
Priyanka

Reputation: 1875

As your recyclerview is a nullable property, You need to modify your code as below -

 recyclerView?.setLayoutManager(GridLayoutManager(activity, 3))

Remove abstract from class

inner class LoadData : AsyncTask<String?, Void?, String>() 

Upvotes: 1

Related Questions