简体   繁体   中英

Sending Data from Activity to Fragment Using Arguments (Kotlin/Android)

I am trying to send data from an Activity to it's child fragment. I have one activity that first loads all the fragments like this:

    view_pager.adapter = TabsAdapter(supportFragmentManager)
    tab_layout.setupWithViewPager(view_pager)

TabsAdapter here is just an if condition for a tab carousel that supports swiping and clicking tab headers to change tabs.

After I load the tabs I call a Fuel http request to get weather data from https://openweathermap.org , a very simple API. I successfully retrieve my local weather and can log the output to the console. Where I am stuck is sending the data to the Fragment.

There are a lot of stackoverflow answers to this question. My issue is that I need to do two things:

1) send the data to the fragment, preferably using an argument as this looks simplest and

2) setting some textViews in my fragment to be the value of the weather (display "It's sunny!")

Here is how I am attempting to solve the problem so far:

In my activity, after the data comes back from the http request, I put the data in a bundle and send the bundle to a method inside my fragment class:

 println("success from json request to weatherAPI")
 val weatherArray = result.get().obj().getJSONArray("weather").get(0) as JSONObject
 println("value of main in weatherArray:" + weatherArray["main"])
 println("value of description in weatherArray:" + weatherArray["description"])
 println("value of icon in weatherArray: " + weatherArray["icon"])

 val args = Bundle()
 args.putString("weatherurl",  "http://openweathermap.org/img/w/"+weatherArray["icon"]+".png")
 args.putString("weatherdescription", weatherArray["description"].toString())
 args.putString("weathermain", weatherArray["main"].toString())

 val homeFrag = HomeFragment()
 homeFrag.getWeather(args)

Here is the fragment I am working with. So in onCreateView I set the weathermainView and weatherdescriptionView to items that I have in the layout for the fragment. I have to do this in onCreateView because this is the only place where view is available. I have these as public variables because I need them accessible in my getWeather function.

My getWeather function tries to take the bundle arguments and set them equal to the textViews, however no matter what I do weathermainView and weatherdescriptionView text values are null, and they do not show in my page in the emulator. I had originally thought that I was experiencing a race condition between creating the tab and getting the data in the activity, so I put in a timeout. However, this does not solve the problem either.

Here is the fragment code:

class HomeFragment : Fragment() {
     var weathermainView: TextView?=null
     var weatherdescriptionView:  TextView?=null

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        val view = inflater!!.inflate(R.layout.fragment_home, container, false)

        weathermainView = view.findViewById<TextView>(R.id.textWeatherMain)
        weatherdescriptionView = view.findViewById<TextView>(R.id.textWeatherDescription)
        println("!!!after setting weathermainView in onCreateView!!!")
        println("value of weathermainView " + weathermainView?.text.toString())

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

    fun getWeather(args: Bundle){
        val weatherMain = args.getString("weathermain")
        val weatherDescription = args.getString("weatherdescription")
        val timer = Timer()
        timer.schedule(timerTask {
            println("value of weathermainView BEFORE SETTING" + weathermainView?.text.toString())
            println("value of weatherdescriptionView BEFORE SETTING" + weatherdescriptionView?.text.toString())
            weathermainView?.text =  args.getString("weathermain")
            weatherdescriptionView?.text = args.getString("weatherdescription")
            println("value of weathermainView " + weathermainView?.text.toString())
            println("value of weatherdescriptionView " + weatherdescriptionView?.text.toString())
        }, 10000)

        println("Value of weatherMain: " + weatherMain)
        println("Value of weatherDescription: " + weatherDescription)

    }
}

Here is the command line output I'm seeing:

I/System.out: !!!after setting weathermainView in onCreateView!!!
I/System.out: value of weathermainView hello there home fragment
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
D/OpenGLRenderer: Swap behavior 0
D/EGL_emulation: eglCreateContext: 0x9ab28d60: maj 3 min 0 rcv 3
D/EGL_emulation: eglMakeCurrent: 0x9ab28d60: ver 3 0 (tinfo 0x99bf5790)
E/eglCodecCommon: glUtilsParamSize: unknow param 0x00008cdf
E/eglCodecCommon: glUtilsParamSize: unknow param 0x00008cdf
E/eglCodecCommon: glUtilsParamSize: unknow param 0x00008824
E/eglCodecCommon: glUtilsParamSize: unknow param 0x00008824
D/EGL_emulation: eglMakeCurrent: 0x9ab28d60: ver 3 0 (tinfo 0x99bf5790)
I/System.out: success from json request to weatherAPI
I/System.out: value of main in weatherArray:Rain
I/System.out: value of description in weatherArray:light rain
I/System.out: value of icon in weatherArray: 10d
I/System.out: Value of weatherMain: Rain
I/System.out: Value of weatherDescription: light rain
I/System.out: value of weathermainView BEFORE SETTING: null
I/System.out: value of weatherdescriptionView BEFORE SETTING: null
I/System.out: value of weathermainView null
I/System.out: value of weatherdescriptionView null

Note: !!!after setting weathermainView in onCreateView!!! is the first output, so the tabs must be instantiated before the response comes back from the http request and the getWeather call is made. And both setting the weather variables in the activity and onCreateView of fragment works. But

I/System.out: value of weathermainView BEFORE SETTING: null
I/System.out: value of weatherdescriptionView BEFORE SETTING: null
I/System.out: value of weathermainView null
I/System.out: value of weatherdescriptionView null

So why are these null?

There's no race condition, I can set in onCreatView successfully. I even put in a timeout. I'm very confused, any hints would help.

EDIT:

Here is my TabsAdapter:

class TabsAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager) {
    // Title for tabs
    private val fragmentTitles = arrayOf("Home", "Music", "Map")
    // Return the Fragment associated with a specified position.
    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment()
            1 -> MusicFragment()
            2 -> MapFragment()
            else -> HomeFragment()
        }
    }
    // Return the number of views/fragments available.
    override fun getCount(): Int = 3 // in our case 3 fragments
    // Return title based on position
    override fun getPageTitle(position: Int): CharSequence {
        return fragmentTitles[position]
    }
}

The following line in your code gives you a new instance of HomeFragment:

val homeFrag = HomeFragment()

This instance is not attached to the Activity so there's no need to execute onCreateView() . Because of this, the TextView s are all null .

You want to display the new data in the Fragment which is already attached to the TabLayout . So you need to keep a handle to it in some variable - let's call it homeFragment - and write

homeFragment.getWeather(args);

Looking at your TabsAdapter implementation, I think it's also a good idea to pass args to the Adapter so the Adapter in turn can pass the data to the HomeFragment for the next time it is to be displayed. To achieve this, HomeFragment needs a static instance() method which will take a Bundle parameter and return a HomeFragment instance. Then you can use this method instead of the Constructor.

This post shows how to do it in Kotlin.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM