0

In my app I use NavController with Fragments. In some fragments I need to access views on MainActivity layout. I do that in this way:

val fab: FloatingActionButton = requireActivity().findViewById(R.id.fab)

This works properly as expected. However, one view does not want to be called and the findViewById() returns null.

The layout structure is like this. In activity_main.xml

<androidx.drawerlayout.widget.DrawerLayout
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        ....>
        <FrameLayout
            android:id="@+id/frame"
            .... />
        <include
            android:id="@+id/include"
            layout="@layout/app_bar_main" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav"
        .... />
</androidx.drawerlayout.widget.DrawerLayout>

is included app_bar_main.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    ....>

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        ....>

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing"
            ....>
            <com.google.android.material.appbar.MaterialToolbar
                android:id="@+id/toolbar"
                .... />
        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <include
        android:id="@+id/content"
        layout="@layout/content_main" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        .... />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

which includes content_main.xml

<androidx.core.widget.NestedScrollView 
    android:id="@+id/nested"
    ....>

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/host"
        .... />
</androidx.core.widget.NestedScrollView>

The problem is, I need to access the NestedScrollView and although all other views can be accessed, this one on the content_main.xml cannot be accessed and returns null:

java.lang.NullPointerException: requireActivity().findViewById(R.id.nested) must not be null

EDIT:

class HomeFragment : Fragment() {
    private lateinit var drawer: DrawerLayout
    private lateinit var nested: NestedScrollView
    private lateinit var fab: FloatingActionBar
    private lateinit var bng: FragmentHomeBinding
    
    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View {
        setHasOptionsMenu(true)
        bng = FragmentHomeBinding.inflate(layoutInflater, container, false)
        return bng.root
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        drawer = requireActivity().findViewById(R.id.drawer)
        fab = requireActivity().findViewById(R.id.fab)
        nested = requireActivity().findViewById(R.id.nested) // This line throws exception

        .........
    }
}

As you can see, I use viewBinding to handle Fragment's Viewss. I do not think that this might be problem.

Mark Delphi
  • 1,376
  • 1
  • 11
  • 29
  • and where are you calling `requireActivity().findViewById(R.id.nested)` ? – Selvin Dec 15 '20 at 11:34
  • If its an `java.lang.NullPointerException` then i think you should check if the Fragment is in the right `Activity` . Because in case `requireActivity()` is null you be getting a `java.lang.IllegalStateException` . – ADM Dec 15 '20 at 11:44
  • @Selvin I am calling it in Fragment, in `onViewCreated()` just like other views, which work properly, but not this one, unfortunately. – Mark Delphi Dec 15 '20 at 11:48
  • @ADM In my project, I have only two activities and all views I try to call are hosted on `MainActivity.kt`. Another one is just a `SplashActivity.kt` and does not include any views and is isolated from the main one. – Mark Delphi Dec 15 '20 at 11:50
  • Note that we prefer a technical style of writing here. We gently discourage greetings, hope-you-can-helps, thanks, advance thanks, notes of appreciation, regards, kind regards, signatures, please-can-you-helps, chatty material and abbreviated txtspk, pleading, how long you've been stuck, voting advice, meta commentary, etc. Just explain your problem, and show what you've tried, what you expected, and what actually happened. – halfer Dec 17 '20 at 00:14

1 Answers1

0

Here is a solution that worked for me. First of all, I found out that I needed to reorder my XML layouts so that put the contents of the content_main.xml and the app_bar_layout.xml directly into the activity_main.xml like this:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer"
    ...>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:id="@+id/coordinator"
            ...>

            <com.google.android.material.appbar.AppBarLayout
                ... >

                <com.google.android.material.appbar.CollapsingToolbarLayout
                    android:id="@+id/collapsing"
                    ... >

                    <com.google.android.material.appbar.MaterialToolbar
                        android:id="@+id/toolbar"
                        ... />

                </com.google.android.material.appbar.CollapsingToolbarLayout>
            </com.google.android.material.appbar.AppBarLayout>

            <androidx.core.widget.NestedScrollView
                android:id="@+id/nested"
                ... >

                <androidx.fragment.app.FragmentContainerView
                    android:id="@+id/host"
                    ... />
            </androidx.core.widget.NestedScrollView>

            <com.google.android.material.floatingactionbutton.FloatingActionButton
                android:id="@+id/fab"
                ... />

        </androidx.coordinatorlayout.widget.CoordinatorLayout>

    </androidx.constraintlayout.widget.ConstraintLayout>


    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav"
        ... />
</androidx.drawerlayout.widget.DrawerLayout>

It might be not an optimal way, but without this step, the Views on content_main.xml could not be accessed, which is rather confusing as before it worked. I've no idea, but it seems that Google changed something in its libraries or whatever that should be.

As a next step, Views you want to access on the activity_main.xml from a certain Fragment, you have to make them public:

MainActivity.kt

class MainActivity : AppCompatActivity() {
    
    ...

    lateinit var fab: FloatingActionButton
    lateinit var nested: NestedScrollView

    ...

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ...

        nested = findViewById(R.id.nested)
        fab = findViewById(R.id.fab)
    
        ...
    }
}

Now, they can be used in a Fragment like this:

MyFragment.kt

class MyFragment : Fragment() {

    ...

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_my, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        ...

        var fab: FloatingActionButton
        var nested: NestedScrollView

        (activity as MainActivity).apply {
            fab = this.fab
            nested = this.nested
        }

        ...
    }
}

That's all - in this way, I could achieve my goals.

halfer
  • 19,824
  • 17
  • 99
  • 186
Mark Delphi
  • 1,376
  • 1
  • 11
  • 29