0

I have bottom navigation activity in my project and contain two fragments. I am trying to pass value from Activity--->FragmentOne and then From FragmentOne--->FragmentTwo. Any help is appreciated.

Language Used

Kotlin

Expectation

1)Pass value from Activity to Fragment
2)Send value from Fragment to Fragment

Error

Null Pointer Exception

Code

Activity

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        var testName:String=intent.getStringExtra("name")
        println("TestCLLicked: $testName")
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
        replaceFragment(TestFragmentOne.newInstance(),TestFragmentOne.TAG)
    }

TestFragmentOne

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            var st:String=arguments!!.getString("name")
             println("TestCLLicked: $testName")

2 Answers2

0

You can go many ways but given your current implementation (using a newInstance), I'd go with using your parent activity as a mediator, going like this:

1) Create a BaseFragment class which your TestFragmentOne and TestFragmentTwo will extend and in there hold a reference to your parent Activity (here named "MainActivity"):

abstract class BaseFragment : Fragment() {

     lateinit var ACTIVITY: MainActivity

     override fun onAttach(context: Context) {
         super.onAttach(context)
         ACTIVITY = context as MainActivity
     }
}

2) Then, in your Activity make sure you declare your variable as a field:

class MainActivity : AppCompatActivity() {

     var textVariable = "This to be read from the fragments"
     ...
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         textVariable = "I can also change this text"
         ...
     }
}

3) Then, from each fragment you can access your variable using the instance inherited from your BaseFragment:

 class TestFragmentOne : BaseFragment() {

      override fun onActivityCreated(savedInstanceState: Bundle?) {
          super.onActivityCreated(savedInstanceState)
          val incomingText = ACTIVITY.textVariable
          println("Incoming text: "+incomingText)

          // You can also set the value of this variable to be read from 
          // another fragment later
          ACTIVITY.textVariable = "Text set from TestFragmentOne"
      }
 }
  • This works correctly as long as you implement onSaveInstanceState to persist that mutable string, and restore it in onCreate if the savedInstanceState bundle is non-null. – EpicPandaForce Jan 03 '19 at 19:35
  • I created BaseFragnent class and followed above approach but still getting null value –  Jan 03 '19 at 19:45
  • 1
    @EpicPandaForce true – Orestis Gartaganis Jan 03 '19 at 19:51
  • @Test when are you getting null value? Reading the variable from your fragments? And what is null, the ACTIVITY or the textVariable? – Orestis Gartaganis Jan 03 '19 at 19:53
  • 1
    println($incomingText) on the TestFragmentOne is null –  Jan 03 '19 at 19:55
  • @Test are you sure you're overriding onActivityCreated and NOT onViewCreated in your fragment? Because that would explain the null value as onViewCreated might be called before activity's onCreate – Orestis Gartaganis Jan 03 '19 at 19:59
  • Created on OnActivity. –  Jan 03 '19 at 20:06
  • @Test this doesn't make much sense. Be careful of the methods you override in the fragments as Activity's onCreate precedes Fragment's onActivityCreated methods and this should work. Otherwise follow EpicPandaForce's advice and insert arguments to your Fragment before replacing it in your replaceFragment method – Orestis Gartaganis Jan 03 '19 at 20:15
-2

For this scenario I use a static Intent and transfer data through it as needed.

    static final Intent storageIntent = new Intent();

    storageIntent.putExtra("name", "value");
  • How to Retrieve this value from fragments? –  Jan 03 '19 at 19:04
  • This is wrong. The intent should not be static. This will be lost after process death and will lose its values. Use Intents for activities and use arguments bundle (setArguments) for Fragments. – EpicPandaForce Jan 03 '19 at 19:32
  • It stays alive when placed in a public class, because it's also final. After the app died, the data isn't needed for exchange any more, I suppose. – Johannes Schidlowski Jan 03 '19 at 19:36
  • You get the data with, for example: String s = storageIntent.getStringExtra("name"); – Johannes Schidlowski Jan 03 '19 at 19:40
  • Thanks for your response but I have tried already and its not working. –  Jan 03 '19 at 19:51
  • @JohannesSchidlowski you are wrong and should refer to https://stackoverflow.com/questions/49046773/singleton-object-becomes-null-after-app-is-resumed/49107399#49107399 – EpicPandaForce Jan 03 '19 at 20:53
  • Ok, I use it every day and in all apps I have, and it works perfectly well across all activities, is painless and uses a "fragment" of memory compared to other solutions. However, if you use fragments and activities across different applications, then you are right, it would not work. – Johannes Schidlowski Jan 05 '19 at 10:16
  • Here is a practical example, created from scratch: https://www.youtube.com/watch?v=EXLnl9Chc8w – Johannes Schidlowski Jan 05 '19 at 18:43