I have isolated the code to show this problem.
I have a recyclerview inside a fragment. I also have LiveData and MutableLiveData.
In the ViewModel.kt code there are these two lines in this order and it works fine:
private val mMLD = MutableLiveData<OneLine>()
var mLD : LiveData<OneLine> = getMLD()
If I reverse the order, ie
var mLD : LiveData<OneLine> = getMLD()
private val mMLD = MutableLiveData<OneLine>()
the program crashes.
Is this a bug?
I am using Android Studio Chipmunk 2021.2.1
Here is my code:
class Adapter(private var mList: List<OneLine>) : RecyclerView.Adapter<Adapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.one_line, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val DisplayViewModel = mList.get(position)
holder.textView.text = DisplayViewModel.text
}
override fun getItemCount(): Int {
return mList.size
}
class ViewHolder(ItemView: View) : RecyclerView.ViewHolder(ItemView) {
val textView: TextView = itemView.findViewById(R.id.textView)
}
}
class Fragment : Fragment() {
private lateinit var adapter : Adapter
private lateinit var viewModel: ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view: View = inflater.inflate(R.layout.fragment, container, false)
viewModel = ViewModelProvider(requireActivity()).get(ViewModel::class.java)
viewModel.Initialize()
enableRecyclerView(view)
viewModel.mLD.observe(viewLifecycleOwner, Observer {
adapter.notifyDataSetChanged()
})
return view
}
fun enableRecyclerView(view:View){
var mRecyclerView: RecyclerView? = null
mRecyclerView = view.findViewById(R.id.recycler_view)
val linearLayoutManager = LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)
mRecyclerView.layoutManager = linearLayoutManager
adapter = Adapter(viewModel.rvData) // This will pass the ArrayList to our Adapter
mRecyclerView.adapter = adapter
}
}
class MainActivity : AppCompatActivity() {
private lateinit var operator_display: ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
data class OneLine(val text: String) {
}
class ViewModel : ViewModel(){
var mLD : LiveData<OneLine> = getMLD() // observer watches this variable
private val mMLD = MutableLiveData<OneLine>()
private fun getMLD():MutableLiveData<OneLine>{return mMLD}
var rvData = ArrayList<OneLine>()
fun Initialize(){
rvData.add(OneLine("Item A"))
rvData.add(OneLine("Item B"))
rvData.add(OneLine("Item C"))
}
}
CodePudding user response:
private val _thing = "hi"
val wow = getThing() // _thing already assigned
fun getThing():String { return _thing }
fun main() {
println(wow)
}
> hi
val wow = getThing() // _thing not assigned yet
private val _thing = "hi"
fun getThing():String { return _thing } // called when assigning wow, _thing not assigned yet
fun main() {
println(wow)
}
> null
When you initialise properties through functions, you can run into issues like this, where the declaration order matters, or the compiler can't tell that a variable is definitely getting initialised somewhere. So here, you're effectively skipping ahead to a function that references a variable before that variable has been assigned
Since it hasn't been assigned yet, it's in its default state, i.e. null. Also notice that it's null even though the function's return type is the non-null String
- the null check system doesn't help you at this point.
You didn't post your actual error, but at a guess it's running into that null and either crashing with a NullPointerException
when you try calling observe
on it, or the null checker is seeing you assign it to something that shouldn't be null, and it's going "hold on a second buddy"