I'm trying to implement an OnClick listener for specific items in a recyclerview. I've done it before with activities, but now I want to do this in a fragment and I've run into a problem. I'm getting the error No value passed for parameter 'click'
. This is the line of code that gives that error:
recyclerAdapterAbstract = abstractList.let {AbstractAdapter(requireActivity(),it)}
This the only error Android Studio is currently showing me. The logcat doesn't show any error. Only the Build Output shows what's wrong and it's exactly what I said earlier
Fragment Class
@Suppress("UNREACHABLE_CODE")
class AbstractWallpapers: Fragment(), PurchasesUpdatedListener, AbstractAdapter.OnItemClickListenerAbstract {
private lateinit var subscribeAbstract: Button
private var billingClient: BillingClient? = null
lateinit var recyclerView: RecyclerView
lateinit var abstractList: ArrayList<Abstract>
private var recyclerAdapterAbstract: AbstractAdapter? = null
private var myRef3: DatabaseReference? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_abstract_wallpaper, container, false)
recyclerView = requireActivity().findViewById(R.id.abstract_recyclerView)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.abstract_recyclerView)
val layoutManager = GridLayoutManager(requireContext(), 2)
recyclerView.layoutManager = layoutManager
recyclerView.setHasFixedSize(true)
myRef3 = FirebaseDatabase.getInstance().reference
abstractList = ArrayList()
ClearAll()
GetDataFromFirebase()
subscribeAbstract = view.findViewById(R.id.abstract_subscribe_btn)
subscribeAbstract.setOnClickListener {
subscribeAbstract()
}
//Establish connection to billing client
//check subscription status from google play store cache
//to check if item is already Subscribed or subscription is not renewed and cancelled
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val queryPurchase = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val queryPurchases = queryPurchase.purchasesList
if (queryPurchases != null && queryPurchases.size > 0) {
handlePurchases(queryPurchases)
} else {
saveSubscribeValueToPref(false)
}
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected", Toast.LENGTH_SHORT).show()
}
})
//item subscribed
if (subscribeValueFromPref) {
subscribeAbstract.visibility = View.GONE
} else {
subscribeAbstract.visibility = View.VISIBLE
}
}
// Code relating to my Firebase storage
@SuppressLint("NotifyDataSetChanged")
private fun GetDataFromFirebase() {
val query: Query = myRef3!!.child("Abstract")
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (dataSnapshot: DataSnapshot in snapshot.children) {
val abstract = Abstract()
abstract.abstract = dataSnapshot.child("abstract").value.toString()
abstractList.add(abstract)}
recyclerAdapterAbstract = abstractList.let {AbstractAdapter(requireActivity(),it)}
recyclerView.adapter = recyclerAdapterAbstract
recyclerAdapterAbstract!!.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {}
})
if (recyclerAdapterAbstract != null) recyclerAdapterAbstract!!.notifyDataSetChanged()
}
private fun ClearAll() {
abstractList.clear()
abstractList = ArrayList()
}
private val preferenceObject: SharedPreferences
get() = requireActivity().getSharedPreferences(PREF_FILE, 0)
private val preferenceEditObject: SharedPreferences.Editor
get() {
val pref = requireActivity().getSharedPreferences(PREF_FILE, 0)
return pref.edit()
}
private val subscribeValueFromPref: Boolean
get() = preferenceObject.getBoolean(SUBSCRIBE_KEY, false)
private fun saveSubscribeValueToPref(value: Boolean) {
preferenceEditObject.putBoolean(SUBSCRIBE_KEY, value).commit()
}
//initiate purchase on button click
fun subscribeAbstract() {
//check if service is already connected
if (billingClient!!.isReady) {
initiatePurchase()
} else {
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
initiatePurchase()
} else {
Toast.makeText(requireActivity(), "Error " billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected ", Toast.LENGTH_SHORT).show()
}
})
}
}
private fun initiatePurchase() {
val skuList: MutableList<String> = ArrayList()
skuList.add(ITEM_SKU_SUBSCRIBE)
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS)
val billingResult = billingClient!!.isFeatureSupported(BillingClient.FeatureType.SUBSCRIPTIONS)
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
billingClient!!.querySkuDetailsAsync(params.build()
) { billingResult, skuDetailsList ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
if (skuDetailsList != null && skuDetailsList.size > 0) {
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList[0])
.build()
billingClient!!.launchBillingFlow(requireActivity(), flowParams)
} else {
//try to add subscription item "sub_example" in google play console
Toast.makeText(requireActivity(), "Item not Found", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(requireActivity(),
" Error " billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(requireActivity(),
"Sorry Subscription not Supported. Please Update Play Store", Toast.LENGTH_SHORT).show()
}
}
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
//if item subscribed
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
handlePurchases(purchases)
}
else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
val queryAlreadyPurchasesResult = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
alreadyPurchases?.let { handlePurchases(it) }
}
else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
Toast.makeText(requireActivity(), "Purchase Canceled", Toast.LENGTH_SHORT).show()
}
else {
Toast.makeText(requireActivity(), "Error " billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
fun handlePurchases(purchases: List<Purchase>) {
for (purchase in purchases) {
//if item is purchased
if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
// Invalid purchase
// show error to user
Toast.makeText(requireActivity(), "Error : invalid Purchase", Toast.LENGTH_SHORT).show()
return
}
// else purchase is valid
//if item is purchased and not acknowledged
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient!!.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
} else {
// Grant entitlement to the user on item purchase
// restart activity
if (!subscribeValueFromPref) {
saveSubscribeValueToPref(true)
Toast.makeText(requireActivity(), "Item Purchased", Toast.LENGTH_SHORT).show()
recreate(requireActivity())
}
}
} else if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
Toast.makeText(requireActivity(),
"Purchase is Pending. Please complete Transaction", Toast.LENGTH_SHORT).show()
} else if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
saveSubscribeValueToPref(false)
subscribeAbstract.visibility = View.VISIBLE
Toast.makeText(requireActivity(), "Purchase Status Unknown", Toast.LENGTH_SHORT).show()
}
}
}
var ackPurchase = AcknowledgePurchaseResponseListener { billingResult ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
//if purchase is acknowledged
// Grant entitlement to the user. and restart activity
saveSubscribeValueToPref(true)
recreate(requireActivity())
}
}
/**
* Verifies that the purchase was signed correctly for this developer's public key.
*
* Note: It's strongly recommended to perform such check on your backend since hackers can
* replace this method with "constant true" if they decompile/rebuild your app.
*
*/
private fun verifyValidSignature(signedData: String, signature: String): Boolean {
return try {
// To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
val base64Key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhBlajrk5nNjpRTPJjDtGxgtgAeKijz3Wc0KrRKKSCxxsViHl7DhsI sUZfk4Y1jxSg4/3W1uRo/0UASM77XfJIq34bK9KYgoSAGYSuH8Z 4fK/MrPz7dHhsljkAi4GZkv8x9VhZdDdpn2GSHVFaxs8c HBOFp9aWAErHrQhi9/7fYf39pQSTC3WkVcy9xNDZxiiKTfDN3dyEvS0XQ617ZJwqDuRdkU5Aw9 R8r oXyURV/ekgCQkWfCUaTp/jWdySOIcR87Bde24lQAXbvJaL5uAYI4zPwO4sIP1AbXLuDtv3N2rFVmP/1cML/NHDcfI5FOoStz88jzJU26Ngpqu1QIDAQAB"
Security.verifyPurchase(base64Key, signedData, signature)
} catch (e: IOException) {
false
}
}
override fun onDestroy() {
super.onDestroy()
if (billingClient != null) {
billingClient!!.endConnection()
}
}
companion object {
const val PREF_FILE = "MyPref"
const val SUBSCRIBE_KEY = "subscribe"
const val ITEM_SKU_SUBSCRIBE = "abstract_wallpapers"
}
override fun onItemClick(item: String) {
}
}
Adapter class
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>, private val click: OnItemClickListenerAbstract ) :
RecyclerView.Adapter<AbstractAdapter.ViewHolder>() {
interface OnItemClickListenerAbstract{
fun onItemClick(item:String)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.abstract_image_view, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Glide.with(mContext)
.load(abstractList[position].abstract)
.into(holder.imageView)
holder.imageView.setOnClickListener {
val intent = Intent(mContext, AbstractPreview::class.java)
intent.putExtra("abstract", abstractList[position].abstract.toString())
Toast.makeText(mContext, "Fullscreen view", Toast.LENGTH_SHORT).show()
mContext.startActivity(intent)
}
holder.downloadBtn.setOnClickListener {
abstractList.get(position).abstract?.let { it1 -> click.onItemClick(it1) }
}
}
override fun getItemCount(): Int {
return abstractList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.abstractImageView)
val downloadBtn: Button = itemView.findViewById(R.id.abstractDownloadBtn)
}
companion object
}
CodePudding user response:
You have 3 parameters for the class AbstractAdapter
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>, private val click: OnItemClickListenerAbstract )
but you are instantiating the object with only two parameters
AbstractAdapter(requireActivity(),it)
It's expecting the third parameter for the clickListener
AbstractAdapter(requireActivity(),it,this)
(send the Fragment as the third param)