1

I am developing news app and I have implemented livedata with progress bar but I am getting following exception in my code

java.lang.IllegalStateException: pb must not be null
 at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment$initViewModel$2.onChanged(TopHeadlinesFragment.kt:60)
 at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment$initViewModel$2.onChanged(TopHeadlinesFragment.kt:22)
 at androidx.lifecycle.LiveData.considerNotify(LiveData.java:131)
 at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:144)
 at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:442)
 at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:394)
 at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:361)
 at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:300)
 at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:339)
 at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:145)
 at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:131)
 at androidx.fragment.app.Fragment.performStart(Fragment.java:2637)
 at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:915)
 at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
 at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
 at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
 at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
 at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
 at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
 at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
 at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
 at android.os.Handler.handleCallback(Handler.java:873)
 at android.os.Handler.dispatchMessage(Handler.java:99)
 at android.os.Looper.loop(Looper.java:201)
 at android.app.ActivityThread.main(ActivityThread.java:6820)
 at java.lang.reflect.Method.invoke(Native Method)
 at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)

below my TopHeadlinesFragment.kt class

class TopHeadlinesFragment : Fragment() {

    private  var binding: FragmentTopHeadlinesBinding? = null
    private val viewModel by viewModel<MainViewModel>()
    private lateinit var topHeadlinesAdapter: TopHeadlinesAdapter
    // private   val newsRepository: NewsRepository by inject()
    private  var article:List<Article>? = null


    //3
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(
            R.layout.fragment_top_headlines
            , container, false
        )
        val recyclerView = view.findViewById(R.id.recyclerView) as RecyclerView
        val pb = view.findViewById(R.id.pb) as ProgressBar
        topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context, article)
        recyclerView.layoutManager = LinearLayoutManager(context)
        recyclerView.adapter = topHeadlinesAdapter
        initViewModel()

        binding?.lifecycleOwner
        return binding?.root


    }

    private fun initViewModel() {
        viewModel?.sportList?.observe(this, Observer { newList ->
            topHeadlinesAdapter.updateData(newList)
        })

        viewModel?.showLoading?.observe(this, Observer { showLoading ->
            pb.visibility = if (showLoading) View.VISIBLE else View.GONE
        })

        viewModel?.showError?.observe(this, Observer { showError ->
            (showError)
        })

        viewModel?.loadNews()
    }
}

below fragment_top_headlines.xml

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

I have followed all stackoverflow suggestion it did not solve my problem. what I want to know where exactly I am making mistake what I have to in order avoid an exception.

what I have tried

1.Invalidate cache restart 2.clean and rebuild project 3.I have checked that progress bar initialized already. 4.I tried this stackoverflow link as well Android: Progressbar must not be null using Kotlin 5. I have tried progress bar declared as global variable it did not work

below my MainViewModel.kt

@Suppress("UNCHECKED_CAST")
class MainViewModel(val newsRepository: NewsRepository) : ViewModel(), CoroutineScope {
    // Coroutine's background job
    val job = Job()
    // Define default thread for Coroutine as Main and add job
    override val coroutineContext: CoroutineContext = Dispatchers.Main + job

    val showLoading = MutableLiveData<Boolean>()
    val sportList = MutableLiveData<List<Article>>()
    val showError = SingleLiveEvent<String>()

    fun loadNews() {
        // Show progressBar during the operation on the MAIN (default) thread
        showLoading.value = true
        // launch the Coroutine
        launch {
            // Switching from MAIN to IO thread for API operation
            // Update our data list with the new one from API
            val result = withContext(Dispatchers.IO) {
                newsRepository?.getNewsList()
            }
            // Hide progressBar once the operation is done on the MAIN (default) thread
            showLoading.value = false
            when (result) {

                is UseCaseResult.Success<*> -> {
                    sportList.value = result.data as List<Article>
                }
                is Error -> showError.value = result.message
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        // Clear our job when the linked activity is destroyed to avoid memory leaks
        job.cancel()
    }
}

I have tried below provided answers as well it did not solve the issue

Edgar
  • 860
  • 1
  • 17
  • 38
  • Not sure but just thinking if val pb is not global and only available in the method onCreateView try making it global and check if it works – Manoj Mohanty Mar 18 '20 at 19:34
  • what is your suggestion it is still appearing I have declared as global but it is still app crashing giving above exception – Edgar Mar 18 '20 at 19:40
  • yes I want to know where I am making mistake – Edgar Mar 18 '20 at 19:44
  • Are you using dataBinding? the other way would be just comment the code which throws the error and validate if your recyclerview is updated post data load – Manoj Mohanty Mar 18 '20 at 19:51
  • next would be to put a debugger at exact location and validate why is null – Manoj Mohanty Mar 18 '20 at 19:52
  • yes I am using databinding but i am still new for data binding thats why what is your suggestion can explain with coding sample – Edgar Mar 18 '20 at 19:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/209874/discussion-between-sashabeliy-and-manoj-mohanty). – Edgar Mar 18 '20 at 19:54

2 Answers2

0

you had not initialized your binding:

 private  var binding: FragmentTopHeadlinesBinding? = null

it is still null

Nurseyit Tursunkulov
  • 8,012
  • 12
  • 44
  • 78
0
    viewModel?.sportList?.observe(this, Observer { newList ->
        topHeadlinesAdapter.updateData(newList)
    })

    viewModel?.showLoading?.observe(this, Observer { showLoading ->
        pb.visibility = if (showLoading) View.VISIBLE else View.GONE
    })

    viewModel?.showError?.observe(this, Observer { showError ->
        (showError)
    })

Should be

    viewModel.sportList.observe(viewLifecycleOwner) { newList ->
        topHeadlinesAdapter.updateData(newList)
    }

    viewModel.showLoading.observe(viewLifecycleOwner) { showLoading ->
        pb.visibility = if (showLoading) View.VISIBLE else View.GONE
    }

    viewModel.showError.observe(viewLifecycleOwner) { showError ->
        (showError)
    }

You might want to make viewModel into lateinit var.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428