问题
So I have two data classes (OutletListDataClass
and ProductListDataClass
) that are currently used by two different fragments (OutletListFragment.kt
and ProductListFragment.kt
, directly connected in navigation graph.).
Both of there fragments are RecyclerView. I want to extract the information from clicked item in OutletListFragment.kt
(That contained in the two data classes) and pass it to ProductListFragment.kt
.
These are the data classes I use in both fragments:
OutletListDataClass
data class OutletListPOJODataClasses(
@SerializedName("data")
@Expose
var data: List<OutletListPOJODataClassesDataItem>? = null,
@SerializedName("error")
val error: OutletListDataClassError? = null
)
data class OutletListPOJODataClassesDataItem(
@SerializedName("stk_prodcode")//Both data classes have this variable
@Expose
val stkProdcode: String? = null,
@SerializedName("stk_allqty")
@Expose
val stkAllqty: Int? = null,
@SerializedName("skt_lastupdate")
@Expose
val sktLastupdate: String? = null,
@SerializedName("outlet_address")
@Expose
val outletAddress: String? = null,
@SerializedName("outlet_name")
@Expose
val outletName: String? = null,
@SerializedName("stk_outcode")
@Expose
val stkOutcode: String? = null
)
ProductListDataClass
data class ProductListPOJODataClasses(
@field:SerializedName("data")
val data: List<ProductListPOJODataClassesDataItem?>? = null,
@field:SerializedName("error")
val error: ProductListDataClassError? = null
)
data class ProductListDataClassError(
@field:SerializedName("msg")
val msg: String? = null,
@field:SerializedName("code")
val code: Int? = null,
@field:SerializedName("status")
val status: Boolean? = null
)
data class ProductListPOJODataClassesDataItem(
@field:SerializedName("stk_prodcode") //Both data classes have this variable
val stkProdcode: String? = null,
@field:SerializedName("stk_allqty")
val stkAllqty: Int? = null,
@field:SerializedName("pro_saleprice")
val proSaleprice: Int? = null,
@field:SerializedName("skt_lastupdate")
val sktLastupdate: String? = null,
@field:SerializedName("stk_outcode")
val stkOutcode: String? = null,
@field:SerializedName("pro_name")
val proName: String? = null
)
As You can see, these two data Classes contains the sa.me variable (StkOutcode). And That's what I want to extract (From OutletListDataItem
)
Here's the code snippet of the current OutletListFragment.kt
:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
(activity as AppCompatActivity).supportActionBar?.title = "Product List"
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_product_stock_outlet_list,
container,
false
)
//Show Progressbar While loading data
showProgressBar()
//Apply layout manager
binding.rvOutletList.layoutManager = LinearLayoutManager((activity as AppCompatActivity))
//Fetch Outlet List Data
fetchOutletListData()
// Declare that this fragment has menu
setHasOptionsMenu(true)
// Set action bar title to "Outlet List"
(activity as AppCompatActivity).supportActionBar?.title = "Outlet List"
return binding.root
}
And this is the recyclerview adapter I created for OutletListFragment. OutletListAdapter
class OutletListItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(
outlet: OutletListPOJODataClassesDataItem,
clickListener: OutletListOnItemClickListener?
) {
itemView.outletName.text = outlet.outletName
itemView.setOnClickListener {
clickListener?.onItemClicked(outlet)
}
}
}
class OutletListAdapter(private var outletList: OutletListPOJODataClasses, private val itemClickListener: OutletListOnItemClickListener)
: RecyclerView.Adapter<OutletListItemHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OutletListItemHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.outlet_list_item_layout, parent, false)
return OutletListItemHolder(v)
}
override fun getItemCount(): Int = outletList.data!!.size
override fun onBindViewHolder(holder: OutletListItemHolder, position: Int) {
val outlet = outletList.data?.get(position)
if (outlet != null) {
holder.bind(outlet, itemClickListener)
}
}
}
interface OutletListOnItemClickListener{
fun onItemClicked(outlet: OutletListPOJODataClassesDataItem)
}
How I can get the variable I want from the Data class in OutletListFragment.kt
and pass it to ProductListFragment.kt
? If there's anything unclear, let me know.
Edit:
This is the snippet of the navigation.xml
:
<fragment
android:id="@+id/productStockOutletList"
android:name="com.example.switchingandroidappproject.mainFragments.ProductStockOutletListFragment"
android:label="ProductStockOutletList" >
<action
android:id="@+id/action_productStockOutletList_to_productListFragment"
app:destination="@id/productListFragment"
app:enterAnim="@android:anim/slide_in_left"
app:exitAnim="@android:anim/slide_out_right"
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@anim/slide_out_left" />
</fragment>
<fragment
android:id="@+id/productListFragment"
android:name="com.example.switchingandroidappproject.mainFragments.ProductListFragment"
android:label="ProductListFragment" />
回答1:
If you are using Jetpack Navigation (and as you are referring to things like "navigation graphs", so clearly you are using Jetpack Navigation), then to pass arguments between navigation destinations, you must define an <action
with the right arguments
that is then passed as some variant of parcelable data to the other fragment.
This is the example from the docs:
<action android:id="@+id/startMyFragment" app:destination="@+id/myFragment"> <argument android:name="myArg" app:argType="integer" android:defaultValue="1" /> </action>
So in your case, it should like you need something like
<navigation ...>
<action android:id="@+id/toProductListFragment"
app:destination="@+id/productListFragment">
<argument
android:name="stkProdcode"
app:argType="string" />
</action>
Apparently this stuff only works if you also enable the safeargs
plugin (as otherwise you have to "remember" this key yourself, or write the NavDirections
class by hand, or put together the Bundle
yourself - either way, Jetpack Navigation expects you to use Safeargs to pass arguments):
buildscript {
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.2"
And
apply plugin: "androidx.navigation.safeargs.kotlin"
And then you should be able to do
class OutletListFragment: Fragment(), OutletListOnItemClickListener {
....
override fun onItemClicked(outlet: OutletListPOJODataClassesDataItem) {
Navigation.findNavController(view).navigate(NavigationDirections.toProductListFragment(outlet.stkProdcode))
}
}
And due to limitations of Jetpack Navigation, you also have to duplicate the argument definition into the <fragment
tag as well:
<fragment
android:id="@+id/productListFragment"
android:name="com.example.switchingandroidappproject.mainFragments.ProductListFragment"
android:label="ProductListFragment" >
<argument
android:name="stkProdcode"
app:argType="string" />
</fragment>
Make sure not to make a typo (android:name
mismatch) as you'd run into unexpected failures).
Now you can obtain your arguments on the other side as
val args = ProductListFragmentArgs.fromBundle(getArguments())
val code = args.stkProdcode
I don't really use Jetpack Navigation, so I'm surprised to see that you have to duplicate the fragment args to the action args, but there you have it.
...to think with what I use in place of Jetpack Navigation, this is as simple as
// send
backstack.goTo(ProductListScreen(stkProdCode))
// receive
val prodCode = getKey<ProductListScreen>().stkProdCode
And is just as (if not more) type-safe. 🙄 *grumble* *grumble* but that doesn't help your case, that's not Jetpack Navigation.
来源:https://stackoverflow.com/questions/62151721/android-kotlin-get-data-from-a-clicked-item-in-recyclerview-and-pass-it-between