Search code examples
androidandroid-fragmentskotlinandroid-tablayout

textView Nullpointer exception when casted in similar conditions


Background
I am populating the textview and imageview dynamically for standarized fragments.
Instead of creating 6 Fragment Layouts and activities, I created 3 and I am setting text/images as needed. This way I would be able to save time and memory instead of creating one fragment per activity when the only thing that changes is the text in the textView and imageView.
Problem
When it reaches the Fragment 3, I get a nullpointer when the implementation is the same as FragmenFirst,FragmentSecond and I do not why.
Code
Page adapter which populates the tablayout

package com.company.app

import android.support.v4.app.Fragment 
import android.support.v4.app.FragmentManager 
import android.support.v4.app.FragmentPagerAdapter


class CustomPageAdapter(FragManager:FragmentManager): FragmentPagerAdapter(FragManager) {
    var fragManagerItems:ArrayList<Fragment> = ArrayList()
    var fragManagerTitles:ArrayList<String> = ArrayList()
    fun removeFragments()
    {
    fragManagerItems.clear()
    }
    fun addFragments(fragmentItem:Fragment,fragmentTitle:String)
    {
    fragManagerItems.add(fragmentItem)
    fragManagerTitles.add(fragmentTitle)

    override fun getItem(position: Int): Fragment {
        return fragManagerItems[position]
    }

    override fun getCount(): Int {
        return fragManagerItems.size
    }
    override fun getPageTitle(position: Int): CharSequence {
        return fragManagerTitles[position]
    }

Fragments are standard, nothing have changed

class FragmentFirst : Fragment() {

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment "

        return inflater!!.inflate(R.layout.fragment_fragment_first, container, false)

    }

Second

class FragmentSecond : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        return inflater!!.inflate(R.layout.fragment_fragment_second, container, false)
    }


}

Third

class FragmentThird : Fragment() {

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        return inflater!!.inflate(R.layout.fragment_fragment_third, container, false)
    }


}

Portion where Main Activity change the textViews of each

import android.os.Bundle import android.support.design.widget.NavigationView import android.support.design.widget.TabLayout import android.support.v4.view.GravityCompat import android.support.v7.app.ActionBarDrawerToggle import android.support.v7.app.AppCompatActivity import android.view.Menu import android.view.MenuItem import com.company.app.fragments.* import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.app_bar_main.* import kotlinx.android.synthetic.main.content_appbar_main.* import kotlinx.android.synthetic.main.fragment_fragment_first.* import kotlinx.android.synthetic.main.fragment_fragment_second.* import kotlinx.android.synthetic.main.fragment_fragment_third.*

class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
    var objPageAdapter:CustomPageAdapter?=null

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

override fun onNavigationItemSelected(item: MenuItem): Boolean {
        // Handle navigation view item clicks here.
        objPageAdapter = CustomPageAdapter(supportFragmentManager)

        when (item.itemId) {
            R.id.nav_fruits -> {
                objPageAdapter!!.removeFragments()
                objPageAdapter!!.addFragments(FragmentFirst(),getString(R.string.txt_tab_fruits_Element_1))
                objPageAdapter!!.addFragments(FragmentSecond(),getString(R.string.txt_tab_fruits_Element_2))
                objPageAdapter!!.addFragments(FragmentThird(),getString(R.string.txt_tab_fruits_Element_3))
                ViewPagerMain.adapter = objPageAdapter
                TabLayoutMain.setupWithViewPager(ViewPagerMain)
                this.textViewFragment_1.text = getString(R.string.txt_txtView_fruits_Element_1)
                this.textViewFragment_2.text = getString(R.string.txt_txtView_fruits_Element_2)
                this.textViewFragment_3.text = getString(R.string.txt_txtView_fruits_Element_3)

...

Error

enter image description here

Xml Fragment 2 and 3 as sample

Fragment 2

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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=".fragments.FragmentSecond">


    <ImageView
        android:id="@+id/imageViewFragment_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/ic_banana" />

    <TextView
        android:id="@+id/textViewFragment_2"
        android:layout_width="match_parent"
        android:layout_height="261dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true" />

</RelativeLayout>

Fragment 3

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".fragments.FragmentThird">



    <ImageView
        android:id="@+id/imageViewFragment_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/ic_banana" />

    <TextView
        android:id="@+id/textViewFragment_3"
        android:layout_width="match_parent"
        android:layout_height="261dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true" />

</RelativeLayout>


Approaches used
1. Clear/Rebuild Project
2. Shutdown/Restart PC

EDIT:Per request, I paste the stacktrace that I am getting

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.company.app, PID: 6790
                  java.lang.IllegalStateException: this.textViewFragment_3 must not be null
                      at com.company.app.MainActivity.onNavigationItemSelected(MainActivity.kt:111)
                      at android.support.design.widget.NavigationView$1.onMenuItemSelected(NavigationView.java:154)
                      at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:822)
                      at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:171)
                      at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:973)
                      at android.support.design.internal.NavigationMenuPresenter$1.onClick(NavigationMenuPresenter.java:342)
                      at android.view.View.performClick(View.java:6294)
                      at android.view.View$PerformClick.run(View.java:24770)
                      at android.os.Handler.handleCallback(Handler.java:790)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      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)

Edit2: To Address Rahul answer
Embedded code in the Main Activity

...
ViewPagerMain.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
                override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
                private lateinit var fr: Fragment
                private lateinit var viewPager: ViewPager
                private lateinit var textView1:TextView
                private lateinit var textView2:TextView
                private lateinit var textView3:TextView
                override fun onPageSelected(position: Int) {
                    when (position) {
                        0 ->{
                            fr = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.ViewPagerMain + ":" + ViewPagerMain.getCurrentItem())
                            textView1 = fr.textViewFragment_1
                            textView1.text= "test1"
                        }
                        1 ->{
                            fr = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.ViewPagerMain + ":" + ViewPagerMain.getCurrentItem())
                            textView2 = fr.textViewFragment_2
                            textView2.text= "test2"
                        }
                        2 ->{
                            fr = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.ViewPagerMain + ":" + ViewPagerMain.getCurrentItem())
                            textView3.text= "test3"
                        }

Solution

  • Instead of accessing textView in onCreate use onPageChangeListener event

     private lateinit var fr: Fragment;
    private lateinit var viewPager: ViewPager
    private lateinit var textView1:TextView
    private lateinit var textView2:TextView
    private lateinit var textView3:TextView
    override fun onPageSelected(position: Int) {
        when (position) {
            0 ->{
                fr = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.viewPager + ":" + viewPager.getCurrentItem())
    
                textView1 = fr.textViewFragment_1
            }
    
    
    
            1-> {
                fr = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.viewPager + ":" + viewPager.getCurrentItem())
    
                textView2 = fr.textViewFragment_2
    
                textView2.text = "rr"
            }
    
    
    
            2-> {
                fr = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.viewPager + ":" + viewPager.getCurrentItem())
    
                textView3= fr.textViewFragment_3
    
                textView3.text = "tt"
            }
    
        }
    }
    
    override fun onPageScrollStateChanged(state: Int) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
    
    
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        setContentView(R.layout.test_layout)
    
    
    }
    

    use these lines in onPageselected to get instance of current visible fragment

    Fragment fr = getSupportFragmentManager().findFragmentByTag(“android:switcher:” + R.id.pager + “:” + mViewPager.getCurrentItem());
    

    now you can access textview but check if fr instancOf Fragment1 textView1=fr.findViewById(textview1Id) and so os..........