This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
I have an app that has MainActivity but all the work is in the fragment.
I made the fragment layout the HomePage using JetPack navigation. and it worked. but when i added the recycler view it crashed.
the error was this:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.saheralsous.android, PID: 12418
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.saheralsous.android/com.saheralsous.android.MainActivity}: android.view.InflateException: Binary XML file line #20 in com.saheralsous.android:layout/activity_main: Binary XML file line #20 in com.saheralsous.android:layout/activity_main: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: android.view.InflateException: Binary XML file line #20 in com.saheralsous.android:layout/activity_main: Binary XML file line #20 in com.saheralsous.android:layout/activity_main: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #20 in com.saheralsous.android:layout/activity_main: Error inflating class fragment
Caused by: java.lang.NullPointerException: null cannot be cast to non-null type androidx.recyclerview.widget.RecyclerView
at com.saheralsous.android.PhotoGalleryFragment.onCreateView(PhotoGalleryFragment.kt:45)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:392)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:140)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:319)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:298)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:699)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:195)
at com.saheralsous.android.MainActivity.onCreate(MainActivity.kt:9)
at android.app.Activity.performCreate(Activity.java:8000)
E/AndroidRuntime: at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
I didn't add or change anything in the main activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
only in the activity_main i added the fragment for Navigation compnonent
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
i initialize the recyclerview in the fragment this way:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
/**
* PagingDataAdapter
*/
RecyclerViewPhotoAdapter = RecyclerViewPhotoAdapter()
/**
* Recycler View
*/
PhotoRecyclerView =
view?.findViewById(R.id.recyclerview_main) as RecyclerView
PhotoRecyclerView.layoutManager = LinearLayoutManager(context)
//linking adapter with recyclerview
PhotoRecyclerView.adapter = RecyclerViewPhotoAdapter
/**
* Adapter, Repository and viewmodel
*/
pagingAdapter = PhotoPaging(
(requireActivity().application as MyApplication).networkApi
)
repository = GalleryFlowRepositoryImpl(pagingAdapter)
viewModel = ViewModelProvider(this, ViewModelProviderFactory(
PhotoGalleryViewModel::class
){
PhotoGalleryViewModel(repository)
}).get(PhotoGalleryViewModel::class.java)
//observing data
observers()
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_photo_gallery, container, false)
}
fragment_photo_gallery layout is simply this
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PhotoGalleryFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</FrameLayout>
In your onCreateView you access the view before inflating the layout.
At line:
PhotoRecyclerView = view?.findViewById(R.id.recyclerview_main) as RecyclerView
you try to retrieve the recyclerview_main in the view wich is null because at this point the layout is not inflated.
Then you force cast it into a RecyclerView (as RecyclerView instead of as? RecyclerView for optional cast) wich lead to a NullPointerExcepion.
I would recommand moving your code into onViewCreated method.
ok it's not a big problem you need to inflate before you use view
first, add this on the top of your onCreateView
val view = inflater.inflate(R.layout.fragment_photo_gallery, container, false)
then return view at the end
return view
hope my answer helped you
I found problem in your code.
You didn't inflate view before use RecyclerView.
PhotoRecyclerView =
view?.findViewById(R.id.recyclerview_main) as RecyclerView
In there, view should be null. because you didn't inflate view.
So to resolve your problem, there are two methods.
First, in onCreateView method you should inflate view before using.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var view = inflater.inflate(R.layout.fragment_photo_gallery, container, false)
/**
* PagingDataAdapter
*/
RecyclerViewPhotoAdapter = RecyclerViewPhotoAdapter()
/**
* Recycler View
*/
PhotoRecyclerView =
view?.findViewById(R.id.recyclerview_main) as RecyclerView
PhotoRecyclerView.layoutManager = LinearLayoutManager(context)
//linking adapter with recyclerview
PhotoRecyclerView.adapter = RecyclerViewPhotoAdapter
/**
* Adapter, Repository and viewmodel
*/
pagingAdapter = PhotoPaging(
(requireActivity().application as MyApplication).networkApi
)
repository = GalleryFlowRepositoryImpl(pagingAdapter)
viewModel = ViewModelProvider(this, ViewModelProviderFactory(
PhotoGalleryViewModel::class
){
PhotoGalleryViewModel(repository)
}).get(PhotoGalleryViewModel::class.java)
//observing data
observers()
// Inflate the layout for this fragment
return view
}
Or Second, you can use your code in onViewCreated method.
Related
I want to navigate to Profile Fragment, when the user wants to sign up. The LoginBottomSheetFragment is responsible to perform this navigation whenever it pops up from the bottom and user clicks on the button. The problem is that whenever I am trying to use findNavController I get the error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.fjklabs.pkfinance, PID: 8711
java.lang.IllegalStateException: View android.widget.LinearLayout{32bc1d5 V.E...... ......ID 0,0-1328,935 #7f090188 app:id/rootLayout} does not have a NavController set
at androidx.navigation.Navigation.findNavController(Navigation.java:84)
at androidx.navigation.fragment.NavHostFragment.findNavController(NavHostFragment.java:118)
at androidx.navigation.fragment.FragmentKt.findNavController(Fragment.kt:29)
at com.fjklabs.pkfinance.fragment.LoginBottomDialogFragment$onCreateView$1.onClick(LoginBottomDialogFragment.kt:42)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
This is the current flow:
MainActivity -> Activity A -> Open BottomSheetFragment -> Navigate to Profile Fragment
This is what (some part of) my navigation xml looks like:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main"
app:startDestination="#id/home">
<fragment
android:id="#+id/login_bottom_sheet"
android:name="LoginBottomDialogFragment"
tools:layout="#layout/fragment_login_bottom_dialog">
<action
android:id="#+id/navigate_to_profile"
app:destination="#id/profile"/>
</fragment>
<fragment
android:id="#+id/profile"
android:name="ProfileFragment"
android:label="Account info"
tools:layout="#layout/fragment_profile"/>
</navigation>
BottomSheetDialogFragment:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val rootView = inflater.inflate(R.layout.fragment_login_bottom_dialog, container, false)
btnLogin = rootView.findViewById(R.id.signup_user)
btnLogin.setOnClickListener {
dismiss()
findNavController().navigate(LoginBottomDialogFragmentDirections.navigateToProfile())
}
root = rootView
return rootView
}
Activity A opens BottomSheetFragment:
fun showBottomDialogFragment() {
bottomDialogFragment.show(supportFragmentManager, "LOGIN_DIALOG_FRAGMENT")
}
Since the navigation is part of the MainActivity layout, The problem seems like Activity A does not have any access to NavController. How would get hold of NavController in such scenario?
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.newsapp/com.example.newsapp.ui.MainActivity}:
android.view.InflateException: Binary XML file line #25 in
com.example.newsapp:layout/activity_main: Binary XML file line #25 in
com.example.newsapp:layout/activity_main: Error inflating class
fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
class MainActivity : AppCompatActivity() {
lateinit var viewModel : NewsViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val newsRepository = NewsRepository(ArticleDatabase(this))
val viewModelProviderFactory = NewsViewModelProviderFactory(newsRepository)
viewModel = ViewModelProvider(this, viewModelProviderFactory).get(NewsViewModel::class.java)
bottomNavigationView.setupWithNavController(nav_host_fragment_container.findNavController())
}
<FrameLayout
android:id="#+id/flFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<fragment
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/nav_host_fragment_container"
app:defaultNavHost="true"
app:navGraph="#navigation/news_nav_graph"/>
</FrameLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="56dp"
app:backgroundTint="#color/grey"
app:menu="#menu/bottom_navigation_menu"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"/>
You have two mistakes in the code
First, you name the listview and the listfiles with the same variable name
// look at that in these lines, both of them had the same variable name
private lateinit var list: ListView
val list = dir.listFiles()
Second, the part which makes the exception in this line
val list = dir.listFiles() // dir.listFiles() returns null
check this answer if you want to get a list of files in directory as I understand
I am trying to migrate my project to view binding and I get an exception when I start my app.
My main activity contains a NavHostFragment like so:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
...
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph" />
...
</LinearLayout>
And the first fragment loaded by default in the NavHostFragment is implemented like so:
class ToolListFragment : Fragment(R.layout.fragment_tool_list) {
...
private var _binding: FragmentToolListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentToolListBinding.inflate(layoutInflater, container, false)
return binding.root
}
...
}
And here is the relevant part of the fragment's layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ToolListFragment"
android:orientation="vertical"
android:background="#android:color/white">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill">
<com.google.android.material.tabs.TabItem
android:id="#+id/tab_around_me"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/tool_filter_around_me"/>
<com.google.android.material.tabs.TabItem
android:id="#+id/tab_assigned_to_me"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/tool_filter_assigned_to_me"/>
<com.google.android.material.tabs.TabItem
android:id="#+id/tab_all_tools"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="All"/>
</com.google.android.material.tabs.TabLayout>
...
</LinearLayout>
As you can see, there is a TabItem with id tab_all. And yet here is the exception that crashes my app:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.herontrack.dev, PID: 12477
java.lang.NullPointerException: Missing required view with ID: com.herontrack.dev:id/tab_all_tools
at com.herontrack.databinding.FragmentToolListBinding.bind(FragmentToolListBinding.java:133)
at com.herontrack.databinding.FragmentToolListBinding.inflate(FragmentToolListBinding.java:78)
at com.herontrack.ToolListFragment.onCreateView(ToolListFragment.kt:107)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2950)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:515)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3049)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2975)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:543)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3056)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:473)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at com.herontrack.MainActivity.onStart(MainActivity.kt:100)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8024)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
So it crashes on this line in ToolListFragment.onCreateView()
_binding = FragmentToolListBinding.inflate(layoutInflater, container, false)
But I really don't understand why.
The problem that you are facing is that TabItem is just a dummy view. Looking in the source code you can see that
/**
* TabItem is a special 'view' which allows you to declare tab items for a {#link TabLayout} within
* a layout. This view is not actually added to TabLayout, it is just a dummy which allows setting
* of a tab items's text, icon and custom layout. See TabLayout for more information on how to use
* it.
*
* #attr ref com.google.android.material.R.styleable#TabItem_android_icon
* #attr ref com.google.android.material.R.styleable#TabItem_android_text
* #attr ref com.google.android.material.R.styleable#TabItem_android_layout
* #see TabLayout
*/
//TODO(b/76413401): make class final after the widget migration
public class TabItem extends View {
So the ViewBinding fails to find the Tab with the ID that you have specified as this is not added to the view hierarchy.
To fix this you have to remove the id from the TabItem. If you need to access Tab you can use the following code.
// to access first tab
binding.tabs.getTabAt(0)
I found out if your use in fragment:
getLayoutInflater().inflate(R.layout.example_view,
viewgroup, false);
In side of the onCreateView(LayoutInflater, ViewGroup,
Int) method, you can do this and then store var view on it: like:
View variable = getLayoutInflater().inflate(R.layout.example_view,
viewgroup, false);
TabItem item = variable.findViewById(R.id.tabLayoutItem);
/*
Other code
*/
It will work flawlessly. However I hugely agree with #Susan Thapa's answer and currently I am using his solution. Provided this answer just incase's somebody else can't follow that answer, because of xyz reason.
In my android application I created map fragment with MapsFragment class
class MapsFragment : Fragment() {
val callback = OnMapReadyCallback { googleMap ->
val sydney = LatLng(-34.0, 151.0)
googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}
private val viewModel: MapViewModel by lazy {
ViewModelProvider(this).get(MapViewModel::class.java)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentMapsBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
mapFragment?.getMapAsync(callback)
}
}
and fragment_maps.xml layout file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.mobile.viewmodels.MapViewModel" />
</data>
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MapsFragment" />
</layout>
I use
buildFeatures {
dataBinding true
}
option for creating binding. Then when I try bind my MapViewModel in line
val binding = FragmentMapsBinding.inflate(inflater)
I get an error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mobile, PID: 331
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at androidx.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1201)
at androidx.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:719)
at com.mobile.databinding.FragmentMapsBindingImpl.<init>(FragmentMapsBindingImpl.java:25)
at com.mobile.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:58)
at androidx.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:74)
at androidx.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:130)
at androidx.databinding.ViewDataBinding.inflateInternal(ViewDataBinding.java:1368)
at com.mobile.databinding.FragmentMapsBinding.inflate(FragmentMapsBinding.java:68)
at com.mobile.databinding.FragmentMapsBinding.inflate(FragmentMapsBinding.java:54)
at com.mobile.ui.MapsFragment.onCreateView(MapsFragment.kt:45)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManagerImpl.java:2100)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1874)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1830)
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:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I/Process: Sending signal. PID: 331 SIG: 9
How to bind viewModel class properly? Is it possible?
Sorry, I might be late to answer this question but as they say, "Better Late than never."
So for the past two days, I have been trying to do the same thing, i.e., using DataBinding and Maps Fragment together.
I tried using both the methods, i.e., DataBindingUtil and as you did FragmentMapsBinding.
So, there were many errors I can across while trying to implement Data Binding, for starters, there was no DataBinding class generated, which is usually not a problem, except in this case. So, the workaround was to force the compiler to generate DataBinding class by introducing a variable, in your case viewModel in the XML file.
Now the data binding class is finally generated but we get this funny error, saying
Index Out of Bound
Now looking at the last error line which was generated
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at androidx.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1201)
and inspecting the code further inside the file ViewDataBinding.java, we see this.
if (isRoot && tag != null && tag.startsWith("layout")) {
final int underscoreIndex = tag.lastIndexOf('_');
if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) {
final int index = parseTagInt(tag, underscoreIndex + 1);
//ERROR IS GENERATED HERE
if (bindings[index] == null) {
bindings[index] = view;
}
indexInIncludes = includes == null ? -1 : index;
isBound = true;
} else {
indexInIncludes = -1;
}
}
Not what I think the problem was is that the bindings file which we had told the complier to forcefully generate doesn't really have any Views in it and the bindings index.
Data Binding Class -
No. of Views = 0
Index = 0
Now trying to access it gives an error.
BUT WAIT A MINUTE, one might say there is a view present, i.e., fragment. What about this?
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MapsFragment" />
After going through a few of the android docs, I think Fragment is not a View.
So, the workaround I would suggest is using either of the two methods.
replace fragment with androidx.fragment.app.FragmentContainerView -> This will remove the error and as the documentation says
FragmentContainerView is a customized Layout designed specifically for Fragments. It extends FrameLayout, so it can reliably handle Fragment Transactions, and it also has additional features to coordinate with fragment behavior.
have another view in your XML file, an example would be.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MapsFragment" />
</androidx.constraintlayout.widget.ConstraintLayout>
Or you can use both, that's up to you.
Hope this answers your question. Have a great day.
UPDATE :
As per Android Developer Docs:
Fragment
kotlin.Any
↳ androidx.fragment.app.Fragment
Fragment Container View
kotlin.Any
↳ android.view.View
↳ android.view.ViewGroup
↳ android.widget.FrameLayout
↳ androidx.fragment.app.FragmentContainerView
It is evident that fragment does not have View as a SuperClass. Thus, this error is thrown.
The above 2 methods are the best ways to avoid this error since in DataBinding it requires at least 1 View.
Either change fragment tag with androidx.fragment.app.FragmentContainerView
or wrap around fragment with another View or ViewGroup like LinearLayout, FrameLayout, etc.
I am a beginner at programming. I have an error message when I start my app and do not know what to do with the code. Can someone help me please.
Here is my code:
Activity :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val items = ArrayList<String>()
items.add("Test1")
items.add("Test2")
items.add("Test3")
listview1.adapter = Adapter1(this, items)
val transaction1 = supportFragmentManager.beginTransaction()
fragment1Button1.setOnClickListener{
transaction1.replace(R.id.fragment1Platz,Fragment1())
transaction1.commit()
}
}
}
Fragment :
class Fragment1 : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_fragment1, container, false)
}
}
Adapter:
class Adapter1 (context : Context, items : ArrayList<String>) : BaseAdapter() {
private val context: Context = context
private val items: ArrayList<String> = items
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val listeneintrag = LayoutInflater.from(context).inflate(R.layout.adapter1_layout,parent, false)
listeneintrag.findViewById<TextView>(R.id.adapter_textfeld1).text = items.get(position)
return listeneintrag
}
override fun getItem(position: Int): String {
return items.get(position)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getCount(): Int {
return items.size
}
}
Error stacktrace:
2020-02-01 13:37:17.972 10729-10729/? E/AndroidRuntime: FATAL
EXCEPTION: main Process: strauss2002.yannick.fragmentetest, PID: 10729
java.lang.RuntimeException: Unable to start activity
ComponentInfo{strauss2002.yannick.fragmentetest/strauss2002.yannick.fragmentetest.MainActivity}:
java.lang.IllegalStateException: listview1 must not be null at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0) at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106) at
android.os.Looper.loop(Looper.java:164) at
android.app.ActivityThread.main(ActivityThread.java:6494) at
java.lang.reflect.Method.invoke(Native Method) at
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused
by: java.lang.IllegalStateException: listview1 must not be null at
strauss2002.yannick.fragmentetest.MainActivity.onCreate(MainActivity.kt:29)
at android.app.Activity.performCreate(Activity.java:7009) at
android.app.Activity.performCreate(Activity.java:7000) at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0) at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106) at
android.os.Looper.loop(Looper.java:164) at
android.app.ActivityThread.main(ActivityThread.java:6494) at
java.lang.reflect.Method.invoke(Native Method) at
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Here is my updated Main Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listview1=findViewById<ListView>(R.id.listview1)
val items = ArrayList<String>()
items.add("Test1")
items.add("Test2")
items.add("Test3")
listview1.adapter = Adapter1(this, items)
val transaction1 = supportFragmentManager.beginTransaction()
fragment1Button1.setOnClickListener{
transaction1.replace(R.id.fragment1Platz,Fragment1())
transaction1.commit()
}
}
}
And here is the new error message:
2020-02-02 11:15:15.935 12764-12764/strauss2002.yannick.fragmentetest E/AndroidRuntime: FATAL EXCEPTION: main
Process: straus
s2002.yannick.fragmentetest, PID: 12764
java.lang.RuntimeException: Unable to start activity ComponentInfo{strauss2002.yannick.fragmentetest/strauss2002.yannick.fragmentetest.MainActivity}: java.lang.IllegalStateException: listview1 must not be null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.IllegalStateException: listview1 must not be null
at strauss2002.yannick.fragmentetest.MainActivity.onCreate(MainActivity.kt:28)
at android.app.Activity.performCreate(Activity.java:7009)
at android.app.Activity.performCreate(Activity.java:7000)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Here is the xml of the activity_main:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/fragment1Platz"
android:layout_width="410dp"
android:layout_height="495dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent">
</FrameLayout>
<Button
android:id="#+id/fragment1Button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:text="Öffne Fragment 1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.529"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here is the xml of the fragment_fragment1:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment1">
<!-- TODO: Update blank fragment layout -->
<ListView
android:id="#+id/listview1"
android:layout_width="match_parent"
android:layout_height="322dp"/>
</FrameLayout>
Here is the xml of the adapter1_layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/adapter_textfeld1"
android:layout_width="137dp"
android:layout_height="53dp"
android:layout_marginTop="128dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Because you didn't call findViewById for listview1.
Add listview1=findViewById(R.id.yourListViewIdInXml); just after setContentView method of oncreate
Or if you are using kotlin synthetic then make sure that listview1 resides in activity_main.xml file
Update
The problem persists because you are calling findViewById on an id(listview1) which is not available in activity_main.xml. Note that in case of activities, when you call findViewById it searches id in the layout file which is passed in setContentView method, that is activity_main.xml in your case. So when you called findViewById<ListView>(R.id.listview1) it searches listview1 in activity_main.xml, but as we know that there is no view available in activity_main.xml which has id=listview1, so findViewById simply returns null and that's why you are getting this error. So to get rid of this exception change:
val listview1=findViewById<ListView>(R.id.listview1)
to this:
val listview1=findViewById<ListView>(R.id.kontaktliste)
I had the same issue. I resolved just putting the setContentView(activity_layout) in the onResume method.
I don't know why this error hasn't occurred in other activities with a listView
The reason you are getting Null Exception is that you are trying to access listView1 before the fragment view is completely created which means listView1 doesn't exist yet.
So you have to move that part of the code you have in your MainActivity to the onCreateView method of your fragment like so:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val rootView = inflater.inflate(R.layout.fragment_fragment1, container, false)
val items = ArrayList<String>()
items.add("Test1")
items.add("Test2")
items.add("Test3")
//THIS IS HOW YOU REFERENCE YOU VIEWS IN A FRAGMENT IN KOTLIN
rootView.listview1.adapter = Adapter1(this, items)
return rootView
}
And pay attention that in a fragment, you have to reference the views through the inflated rootView for your fragment.