Java 使用参数将数据从活动发送到片段(Kotlin/Android)

Java 使用参数将数据从活动发送到片段(Kotlin/Android),java,android,android-fragments,kotlin,race-condition,Java,Android,Android Fragments,Kotlin,Race Condition,我正在尝试将数据从活动发送到它的子片段。我有一个活动首先加载所有片段,如下所示: view_pager.adapter = TabsAdapter(supportFragmentManager) tab_layout.setupWithViewPager(view_pager) TabsAdapter对于支持滑动和单击选项卡标题以更改选项卡的选项卡旋转木马,这里只是一个if条件 加载选项卡后,我调用Fuel http请求从一个非常简单的API获取天气数据。我成功地检索了本地天气

我正在尝试将数据从活动发送到它的子片段。我有一个活动首先加载所有片段,如下所示:

    view_pager.adapter = TabsAdapter(supportFragmentManager)
    tab_layout.setupWithViewPager(view_pager)
TabsAdapter
对于支持滑动和单击选项卡标题以更改选项卡的选项卡旋转木马,这里只是一个if条件

加载选项卡后,我调用Fuel http请求从一个非常简单的API获取天气数据。我成功地检索了本地天气,并可以将输出记录到控制台。我陷入困境的地方是将数据发送到片段

这个问题有很多答案。我的问题是我需要做两件事:

1) 将数据发送到片段,最好使用参数,因为这看起来很简单 及

2) 将我的片段中的一些文本视图设置为天气值(显示“It's sunny!”)

以下是我目前试图解决问题的方法:

在我的活动中,当数据从http请求返回后,我将数据放入一个捆绑包中,并将捆绑包发送到我的fragment类中的一个方法:

 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)
这是我正在处理的片段。因此,在
onCreateView
中,我将
weathermainView
weatherdescriptionView
设置为片段布局中的项目。我必须在
onCreateView
中执行此操作,因为这是
view
唯一可用的地方。我将这些作为公共变量,因为我需要在我的
getWeather
函数中访问它们

My
getWeather
函数尝试获取捆绑参数并将其设置为与TextView相等,但是无论我做什么,
weathermainView
weatherdescriptionView
文本值都为空,并且它们不会显示在emulator的我的页面中。我原本以为我在创建选项卡和获取活动中的数据之间遇到了竞争条件,所以我设置了一个超时。然而,这也不能解决问题

以下是片段代码:

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)

    }
}
注意:
!!!在onCreateView中设置weathermainView之后
是第一个输出,因此在http请求返回响应并调用
getWeather
之前,必须实例化选项卡都在活动和片段的创建视图中设置天气变量但是

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
那么为什么这些为空?

没有竞争条件,我可以成功设置
onCreatView
。我甚至暂停了。我很困惑,任何提示都会有帮助

编辑:

这是我的标签:

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]
    }
}

代码中的以下行提供了HomeFragment的新实例:

val homeFrag = HomeFragment()
此实例未附加到
活动
,因此无需执行
onCreateView()
。因此,
TextView
s都是
null

您希望在已附加到
表格布局的
片段中显示新数据。因此,您需要在某个变量中保留一个句柄—我们称之为homeFragment—并编写

homeFragment.getWeather(args);
查看您的
TabsAdapter
实现,我认为将args传递给适配器也是一个好主意,这样适配器就可以将数据传递给
HomeFragment
,以便下次显示它。要实现这一点,
HomeFragment
需要一个静态的
instance()
方法,该方法将获取一个Bundle参数并返回一个
HomeFragment
实例。然后可以使用此方法而不是构造函数


这显示了如何在Kotlin中执行此操作。

在创建的活动上或视图上写入与捆绑包相关的代码。
您可能不会收到错误。。如果有用就更新..嗯..我不知道怎么做。我尝试像这样传递活动中的参数:`homeFrag.arguments.putString(someweatherstring)
。在
onViewCreated`我有
val weatherurl=arguments.getString(“weatherurl”)
但这会产生错误
java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法'java.lang.String android.os.Bundle.getString(java.lang.String)'
。在片段中,
arguments
应该是的修饰符是什么?首先你需要像
getArguments()
这样获取参数,记住,这是在Kotlin中,所以get/setArguments()现在是arguments。它的语法稍有不同,我也有类似的问题。你解决你的问题了吗?你能告诉我哪里不对吗?这是一个很好的观点。我已经把我的标签贴出来了。也许我应该在那里写一个函数,以某种方式获取片段类……但不确定。我必须承认我有点迷路了,我还没见过这么多关于如何在TabAdapter中处理片段的帖子。@Peter Weyand-就像我编辑过的答案所说的:你使用的不是HomeFragment(),而是HomeFragment.instance(args),但我必须承认这是一个简单的旧Java,不知道如何在Kotlin中说出来。但我会努力找出答案,然后back@PeterWeyand-在堆栈溢出上发现了一些东西,我希望它有用。我感谢您的洞察力。仍然有问题-我现在的问题是异步的。因此,如果我调用
TabsAdapter.newInstanceHome(“weatherurl”)http://openweathermap.org/img/w/“+weatherArray[“icon”]+“.png”)
在我的rest调用中,并且在
onCreateView
中,我有
val bdl:Bundle=arguments
arguments将为null并引发错误。为什么?因为
onCreateView
在rest调用完成之前激发。我可以在片段中执行其他生命周期方法,但我只是希望片段满足竞争条件。@Peter Weyand-在刷新时显示旧数据或“加载…”不是更好吗?一旦有新数据,就发布它们?您的TabsAdapter可以有一个方法刷新(位置:Int,args:Bun)
homeFragment.getWeather(args);