1

I want to access the late init variable in more than two functions how can i use it? Actually I want to remove the item from recyclerview when request accept or declined

1. Here is my fragment class

lateinit var adapterPendingRequest: FriendsPendingRequestAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    floatingActionButton = view.findViewById(R.id.addFriendFloatingButton)

    recyclerPendingRequest = view.pendingRequestsRecyclerId
    recyclerPendingRequest.layoutManager = LinearLayoutManager(requireContext())

    recyclerViewFriendList = view.friendListRecyclerView
    recyclerViewFriendList.layoutManager = LinearLayoutManager(requireContext())
    adapterPendingRequest = FriendsPendingRequestAdapter(activity!!)


    floatingActionButton.setOnClickListener {
        findNavController().navigate(R.id.action_friendListFragmentId_to_searchFriendFragment)
    }

    actionMoreButton = view.moreMenuOptionId
    actionMoreButton.setOnClickListener {
        showPopup()
    }


    //Get FriendRequest Function
    getFriendRequest()

    //FriendList
    addedFriendsList()

    Log.e("size", modelPendingRequest.size.toString())

}  

2.This adapter working fine in getFriendRequest function this is the function where i am getting the list from server in recyclerview and accepting or decline the request but item didn't removing on button click

private fun getFriendRequest() {
    val getHttpRequest = HttpRequest()

    Log.e("ResponseText","Inside fun")

    getHttpRequest.setOnResponseListener { getRequestResponse ->
        Log.e("ResponseText", getRequestResponse.text)
        Log.e("get ResponseCode", getRequestResponse.code.toString())
        if (getRequestResponse.code == HttpResponse.HTTP_OK) {
            Log.e("get in ResponseCode", getRequestResponse.code.toString())

            val jsonArray = getRequestResponse.toJSONArray()
            modelPendingRequest.clear()
            for (i in 0 until jsonArray!!.length()) {
                val jsonObject = jsonArray.getJSONObject(i)
                val getRequestUserName = jsonObject.getString("username")
                val getRequestImage = jsonObject.getString("image")
                val getRequestFirstName = jsonObject.getString("first_name")
                val getRequestLastName = jsonObject.getString("last_name")

                modelPendingRequest.add(SearchUserModel(getRequestUserName,getRequestImage,getRequestFirstName,getRequestLastName))
                //adapter to set all data in recyclerview
                adapterPendingRequest.setData(modelPendingRequest)
                
                recyclerPendingRequest.adapter = adapterPendingRequest
                Log.e("sizes", modelPendingRequest.size.toString())

                appGlobals.saveString("requestUser", getRequestUserName)
            }

        } else if (getRequestResponse.code != HttpResponse.HTTP_OK) {
            Toast.makeText(requireContext(), getRequestResponse.text, Toast.LENGTH_SHORT).show()
        }
    }

    getHttpRequest.setOnErrorListener {
        Log.e("Get Request Error", it.toString())
    }

    val token = appGlobals.getValueString("userToken")
    Log.e("requestToken", token.toString())
    val headers = HttpHeaders("Authorization", "Token $token")
    getHttpRequest.get(AppGlobals.GET_FRIEND_REQUEST_API, headers)
    Log.e("ResponseText","end of fun")

}}

3. But not here

fun acceptRequest(position: Int) {

    val acceptHttRequest = HttpRequest()
    val jsonObject = JSONObject()
    acceptHttRequest.setOnResponseListener { acceptResponse ->

        Log.e("accept ResponseText", acceptResponse.text)
        Log.e("accept ResponseCode", acceptResponse.code.toString())

        if (acceptResponse.code == HttpResponse.HTTP_OK) {
            Log.e("accept ResponseCode", acceptResponse.code.toString())

            Log.e("sizes", modelPendingRequest.size.toString())

            adapterPendingRequest.removePosition(position)

        }
    }

    acceptHttRequest.setOnErrorListener {
        Log.e("Accept Request Error", it.toString())
    }

    val userName = appGlobals.getValueString("requestUser")
    Log.e("Accept Request", "$userName")

    try {
        jsonObject.put("username", userName)
    } catch (e: JSONException) {
        Log.e("Accept Request Error", "Error here")
    }
    val token = appGlobals.getValueString("userToken")
    val headers = HttpHeaders("Authorization", "Token $token")

    acceptHttRequest.post(AppGlobals.ACCEPT_FRIEND_REQUEST_API, jsonObject, headers)
}

Here is adapter class

Class FriendsPendingRequestAdapter(activity: Activity): RecyclerView.Adapter<FriendsPendingRequestAdapter.RequestViewHolder>() {
    
        private var data = ArrayList<SearchUserModel>()
        private val requestActivity = activity
        private val friendListFragment = FriendListFragment()
        var removedPosition : Int ? = null
    
        class RequestViewHolder(requestView: View): RecyclerView.ViewHolder(requestView) {
    
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RequestViewHolder {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.friend_pending_request_list, parent, false)
            return RequestViewHolder(view)
        }
    
        override fun onBindViewHolder(holder: RequestViewHolder, position: Int) {
            val pendingRequest = data[position]
    
            holder.itemView.friendRequestNameId.text = "${pendingRequest.firstName} ${pendingRequest.lastName}"
            Log.e("Request Name", pendingRequest.firstName)
    
            Glide.with(requestActivity)
                .load("${AppGlobals.SERVER}${pendingRequest.image}")
                .into(holder.itemView.friendRequestImageId)
    
            holder.itemView.confirmRequestButtonId.setOnClickListener {
                requestActivity.let { friendListFragment.acceptRequest(position)
    //            data.removeAt(position)
                removedPosition = position
                notifyDataSetChanged()}
    
            }
    
            holder.itemView.cancelRequestButtonId.setOnClickListener {
                requestActivity.let {friendListFragment.declineRequest(position)
    //                data.removeAt(position)
                    removedPosition = position
                    notifyDataSetChanged()}
    
            }
        }
    
        override fun getItemCount(): Int {
            return data.size
        }
    
        fun setData(tasks: ArrayList<SearchUserModel>) {
            this.data = tasks
            notifyDataSetChanged()
        }
    
        fun removePosition(position: Int): Int? {
            data.removeAt(position)
            notifyDataSetChanged()
            return removedPosition
        }

2 Answers2

0

Your adapter variable in the function twoFun is only adapter instead of adapterPendingRequest. Is that it?

0

Instantiating a fragment manually from within the adapter and accessing it like that doesn't seem appropriate. The lifecycle of Android components need to be managed by Android, so if you just instantiate it yourself like this, there is no way onViewCreated is called on this fragment, and thus the lateinit property won't be initialized inside.

Note that there is a bigger problem: the fragment instantiates the adapter, and the adapter instantiates a fragment. There is no way the adapter is using the same fragment as the one that called its constructor.

One way around it would be to pass the fragment (this) to the constructor of the adapter when you call it in onViewCreated. But I haven't done Android dev for a while, so I'm not sure it's even good practice for the adapter to have access to the containing fragment.

Other important notes:

  • it's usually preferable to use read-only val instead of mutable var, especially for public properties (it makes the code easier to reason about)

  • lateinit var is a trick to use non-nullable properties when you know better than the compiler when it will be initialized and when it is safe to access it - but you're clearly giving up on null-safety for "convenience". Using a public lateinit var is dangerous because it makes it harder to see the exact order of events (when it's initialized VS when it's accessed). In general, as soon as it's public, you can't really rely on knowing more than the compiler - you will likely make mistakes. So keep lateinit var's visibility/scope as small as possible in order to clearly see all accesses and initialization easily

Joffrey
  • 32,348
  • 6
  • 68
  • 100