kotlinandroid-recyclerviewretrofitsearchview

SearchView kotlin can't get data with kotlin and Retrofit


This is the endpoint from server

@Headers("Accept: application/json")
@GET("markets?search=")
suspend fun searchItems(
    @Header("Authorization") bearerToken: String,
    @Query("") keyword: String
): Response<MarketAccessResponse>

this is the model and response

data class Market( val id: Int, val comodity_id: Int, val user_id: Int, val quantity: Int, val estimated_weight_unit_id: Int, val harvest_estimated_start: String, val harvest_estimated_end: String, val price: Int, val price_weight_unit_id: Int, val status: String, val company_name: String, val note: String, val address: String, val photo: String, val latitude: String, val longitude: String, val province_id: Int, val regency_id: Int, val district_id: Int, val village_id: BigInteger, val type: String, val createdAt: String?, val updatedAt: String?, val comodity : Comodity, val estimated_weight_unit : EstimatedWeightUnit, val price_weight_unit : PriceWeightUnit, val province : Provinsi, val regency : Regenci, val district : Distrik, val village : Village, )

class Comodity( val id: Int, val name: String, )

class EstimatedWeightUnit( val id: Int, val unit: String, )

class PriceWeightUnit( val id: Int, val unit: String, )

class Provinsi( val id: String, val name: String, )

class Regenci( val id: String, val name: String, )

class Distrik( val id: String, val name: String, )

class Village( val id: String, val name: String, )

data class MarketAccessResponse( val data: List, val message: String, val error: Boolean )


My Adapter Class

class MarketItemAdapter(private val items: List<Market> = mutableListOf())
    : RecyclerView.Adapter<MarketItemAdapter.ViewHolder>() {

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private val ivMarketAccess: ImageView = itemView.findViewById(R.id.img_market_access)
        private val tvCompanyAccess: TextView = itemView.findViewById(R.id.tv_company_access)
        private val tvProductMarket: TextView = itemView.findViewById(R.id.tv_product_market)
        private val tvProductDescription: TextView = itemView.findViewById(R.id.tv_product_description)
        private val tvProductLocation: TextView = itemView.findViewById(R.id.tv_product_location)
        private val tvMarketStatus: TextView = itemView.findViewById(R.id.tv_market_status)
        private val tvMarketStatusSuccess: TextView = itemView.findViewById(R.id.tv_market_status_success)
        private val btnMarketStatusPending: ConstraintLayout = itemView.findViewById(R.id.btn_market_status_pending)
        private val btnMarketStatusSuccess: ConstraintLayout = itemView.findViewById(R.id.btn_market_status_success)
        private val btnFillDetail: LinearLayout = itemView.findViewById(R.id.btn_fill_Detail)
        fun bind(item: Market) {

            // Set the icon and name values for each item
            Picasso.get()
                .load(item.photo)
                .placeholder(R.drawable.placeholder_potrait) // Placeholder image if the actual image is loading
                .error(R.drawable.placeholder_potrait)
                .fit().centerCrop()// Error image if Picasso fails to load the image
                .into(ivMarketAccess)

            tvCompanyAccess.text = item.company_name
            tvProductMarket.text = item.comodity.name
            tvProductDescription.text =  "kebutuhan ${item.quantity} kg"
            tvProductLocation.text = item.regency.name

            tvMarketStatus.text = item.status
            tvMarketStatusSuccess.text = item.status

            if (tvMarketStatus.text == "tersedia") {
                btnMarketStatusSuccess.isGone = false
                btnMarketStatusPending.isGone = true
            }

            btnFillDetail.setOnClickListener {
                val context = itemView.context
                val i = Intent(context, DetailMarketActivity::class.java)
                i.putExtra("img",item.photo)
                i.putExtra("company-name",tvCompanyAccess.text)
                i.putExtra("note",item.note)
                i.putExtra("address",item.address)
                i.putExtra("pruduct",tvProductMarket.text)
                i.putExtra("stock",item.quantity.toString())
                i.putExtra("datetime",item.createdAt)
                i.putExtra("location",item.regency.name)
                i.putExtra("available",tvMarketStatus.text)
                i.putExtra("pending",tvMarketStatusSuccess.text)
                context.startActivity(i)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_market_access, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(items[position])
    }

    override fun getItemCount(): Int {
        return items.size
    }

    fun getItem(position: Int): Market {
        return items[position]
    }

    fun setItems(newItems: List<Market>) {
//        items.clear()
//        items.addAll(newItems)
        notifyDataSetChanged()
    }

}
this is my activity
class MarketAccessActivity : AppCompatActivity() {

    private lateinit var ivBack : ImageView
    private lateinit var rvMarket: RecyclerView
    private lateinit var adapter: MarketItemAdapter
    private lateinit var searchView: SearchView



    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_market_access)

        ivBack = findViewById(R.id.iv_back)
        ivBack.setOnClickListener {
            startActivity(Intent(this@MarketAccessActivity, HomeActivity::class.java))
            finish()
        }

        searchView = findViewById(R.id.searchView)
        adapter = MarketItemAdapter()
        rvMarket = findViewById(R.id.rv_market_access)
        val layoutManager = GridLayoutManager(this, 2)
        rvMarket.layoutManager = layoutManager
        getMarketAccess()


        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                return false
            }

            override fun onQueryTextChange(newText: String): Boolean {
                searchItems(newText)
                return false
            }
        })

    }

    private fun searchItems(keyword: String) {
        // Retrieve tokens
        val (savedToken, savedRefreshToken) = SharedPrefsUtil.getTokens(this@MarketAccessActivity)
        if (savedToken != null && savedRefreshToken != null) {
            CoroutineScope(Dispatchers.IO).launch {
                val apiService = ApiClient.apiService.searchItems("Bearer $savedToken",keyword)
                try {
                    if (apiService.isSuccessful) {
                        val items = apiService.body()?.data
                        runOnUiThread {
                            adapter.setItems(items.orEmpty())
                            rvMarket.adapter = adapter
                        }
                        Log.d("data-search", apiService.body().toString() )
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    Log.d("$e", keyword )
                }
            }
        }
    }

    private fun getMarketAccess() {
        // Retrieve tokens
        val (savedToken, savedRefreshToken) = SharedPrefsUtil.getTokens(this@MarketAccessActivity)
        if (savedToken != null && savedRefreshToken != null) {

            // Show progress dialog
            val progressDialog = ProgressDialog(this@MarketAccessActivity)
            progressDialog.setMessage("Loading data...")
            progressDialog.setCancelable(false)
            progressDialog.show()

            val call = ApiClient.apiService.getMarketList("Bearer $savedToken")
            call.enqueue(object : Callback<MarketAccessResponse> {
                override fun onResponse(call: Call<MarketAccessResponse>, response: Response<MarketAccessResponse>) {
                    progressDialog.dismiss() // Dismiss progress dialog on failure

                    if (response.isSuccessful) {
                        val marketResponse = response.body()
                        marketResponse?.let {
                            // TODO: Process the list of lands in landResponse.data
                            // For example, you can access the list using landResponse.data
                            val marketList = marketResponse.data
                            val marketAdapter = MarketItemAdapter(marketList)
                            rvMarket.adapter = marketAdapter
                            Log.d("data-muncul",response.body()?.data.toString())
                        }
                    } else {
                        // Handle API error here
                        // You can extract the error message from the response
                        // using response.errorBody()?.string()
                        Toast.makeText(this@MarketAccessActivity,
                            "Failed to fetch markets", Toast.LENGTH_SHORT).show()
                        Log.e("failed", "Failed fetch data")
                    }
                }

                override fun onFailure(call: Call<MarketAccessResponse>, t: Throwable) {
                    progressDialog.dismiss() // Dismiss progress dialog on failure
                    // Handle network or other errors here
                    Toast.makeText(this@MarketAccessActivity,
                        "Failed to fetch lands", Toast.LENGTH_SHORT).show()
                    Log.e("GetMarketsError", t.toString())
                }
            })
        }
    }
}

I can get a JSON response, but the overall data is not based on the query I entered.


Solution

  • In suspend fun searchItems() of your code, there is a Query parameter that don’t have name specifier.

    @Query("") keyword: String