Home > Enterprise >  Fatal Exception: java.lang.NullPointerException crash event
Fatal Exception: java.lang.NullPointerException crash event

Time:01-19

An error occurs on line 41 when initializing the SongListFragment fragment class. Here is a snippet of the class:

class SongListFragment : Fragment() {

private var _binding: FragmentSongsListBinding? = null
private val binding get() = _binding!! //error
private var player: ExoPlayer? = null
private lateinit var inputManager: InputMethodManager
private lateinit var sharedPreferences: SharedPreferences
private lateinit var editor: SharedPreferences.Editor

private val songListAdapter by lazy {
    SongListAdapter(requireActivity()) { show ->
        showMultipleSelectActionBar(
            show
        )
    }
}

private val viewModel: SongListViewModel by activityViewModels()

@SuppressLint("RtlHardcoded")
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    player = (context as MainActivity).exoPlayer
    inputManager =
        requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

    sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
    editor = sharedPreferences.edit()

    enterTransition = Slide(Gravity.END)
    exitTransition = Fade()
    returnTransition = Fade()
}

@RequiresApi(Build.VERSION_CODES.Q)
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    requireActivity().window.statusBarColor =
        ContextCompat.getColor(requireContext(), R.color.main_background_color)
    if (_binding == null) {
        _binding = FragmentSongsListBinding.inflate(inflater, container, false)
    }
    postponeEnterTransition()
    binding.root.doOnPreDraw { startPostponedEnterTransition() }
    viewModel.getSongList(context)
    initObserver()
    setDataToView()
    searchMusic()
    multipleSelectButtonImplementation()
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    if (sharedPreferences.getInt(Constants.AD_COUNTER, 0) == 3) {
        (activity as MainActivity).showAd(requireContext())
        editor.putInt(Constants.AD_COUNTER, 0)
        editor.commit()
    } else {
        editor.putInt(Constants.AD_COUNTER, (sharedPreferences.getInt(Constants.AD_COUNTER, 0)   1))
        editor.commit()
    }
}

stack trace:

Fatal Exception: java.lang.NullPointerException

example.androidvolumelouder.presentation.ui.fragments.songlistfragment.SongListFragment.getBinding (SongListFragment.kt:41) example.androidvolumelouder.presentation.ui.fragments.songlistfragment.SongListFragment.access$getBinding (SongListFragment.kt:38) example.androidvolumelouder.presentation.ui.fragments.songlistfragment.SongListFragment$setSongCount$1.invokeSuspend (SongListFragment.kt:225) kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) kotlinx.coroutines.DispatchedTaskKt.resume (DispatchedTask.kt:234) kotlinx.coroutines.DispatchedTaskKt.dispatch (DispatchedTask.kt:166) kotlinx.coroutines.CancellableContinuationImpl.dispatchResume (CancellableContinuationImpl.kt:397) kotlinx.coroutines.CancellableContinuationImpl.resumeImpl (CancellableContinuationImpl.kt:431) kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default (CancellableContinuationImpl.kt:420) kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched (CancellableContinuationImpl.kt:518) kotlinx.coroutines.android.HandlerContext$scheduleResumeAfterDelay$$inlined$Runnable$1.run (Runnable.kt:19)

This happens on the first run after installation. And what's more, everything is fine on physical devices with Android 10 on all others and on emulators as well. What is the error, please help?

CodePudding user response:

The crash is not in the above lines.. However, you are accessing binding after you navigate the screen.

You need to safe call isAdded before using binding as follow: e.g.

if(isAdded){
    binding.button.setOnClickListener{ ... }
}

CodePudding user response:

Try to move your UI elements bind logic to onViewCreated

See Fragment  |  Android Developers

Called immediately after onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle) has returned, but before any saved state has been restored in to the view. This gives subclasses a chance to initialize themselves once they know their view hierarchy has been completely created. The fragment's view hierarchy is not however attached to its parent at this point.

For instance:

class SongListFragment : Fragment() {

private var _binding: FragmentSongsListBinding? = null
private val binding get() = _binding!! //error
private var player: ExoPlayer? = null
private lateinit var inputManager: InputMethodManager
private lateinit var sharedPreferences: SharedPreferences
private lateinit var editor: SharedPreferences.Editor

private val songListAdapter by lazy {
    SongListAdapter(requireActivity()) { show ->
        showMultipleSelectActionBar(
            show
        )
    }
}

private val viewModel: SongListViewModel by activityViewModels()

@SuppressLint("RtlHardcoded")
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    player = (context as MainActivity).exoPlayer
    inputManager =
        requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

    sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
    editor = sharedPreferences.edit()

    enterTransition = Slide(Gravity.END)
    exitTransition = Fade()
    returnTransition = Fade()
}

@RequiresApi(Build.VERSION_CODES.Q)
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    requireActivity().window.statusBarColor =
        ContextCompat.getColor(requireContext(), R.color.main_background_color)
    if (_binding == null) {
        _binding = FragmentSongsListBinding.inflate(inflater, container, false)
    }
    postponeEnterTransition()
    
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    binding.root.doOnPreDraw { startPostponedEnterTransition() }
    viewModel.getSongList(context)
    initObserver()
    setDataToView()
    searchMusic()
    multipleSelectButtonImplementation()
    if (sharedPreferences.getInt(Constants.AD_COUNTER, 0) == 3) {
        (activity as MainActivity).showAd(requireContext())
        editor.putInt(Constants.AD_COUNTER, 0)
        editor.commit()
    } else {
        editor.putInt(Constants.AD_COUNTER, (sharedPreferences.getInt(Constants.AD_COUNTER, 0)   1))
        editor.commit()
    }
}
  • Related