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.