Kotlin+Retrofit实现SearchView搜索时数据与查询不匹配问题
问题描述
在Android项目中,使用Kotlin结合Retrofit实现SearchView搜索功能时,虽能获取到JSON响应,但返回的数据与输入的查询关键词不匹配。
核心问题与修复方案
1. Retrofit搜索接口定义错误
原接口手动拼接了search=参数,且@Query的参数名为空,导致请求URL格式错误,后端无法正确接收搜索关键词。
修复后的接口代码:
@Headers("Accept: application/json") @GET("markets") // 移除手动拼接的search参数 suspend fun searchItems( @Header("Authorization") bearerToken: String, @Query("search") keyword: String // 指定正确的参数名"search" ): Response<MarketAccessResponse>
2. 适配器未正确更新数据源
原setItems方法未替换内部数据源,仅调用notifyDataSetChanged,导致RecyclerView始终显示旧数据。
修复后的适配器代码:
// 将items改为可变列表 class MarketItemAdapter(private val items: MutableList<Market> = mutableListOf()) : RecyclerView.Adapter<MarketItemAdapter.ViewHolder>() { // ... 其他代码保持不变 fun setItems(newItems: List<Market>) { items.clear() items.addAll(newItems) notifyDataSetChanged() } }
3. 数据模型泛型缺失
MarketAccessResponse的data字段仅声明为List,未指定泛型List<Market>,可能导致解析时无法正确映射数据。
修复后的MarketAccessResponse:
data class MarketAccessResponse( val data: List<Market>, // 指定泛型为Market val message: String, val error: Boolean )
4. Activity中适配器状态混乱
原代码初始化adapter后,getMarketAccess又新建适配器实例设置给RecyclerView,导致搜索时更新的是未关联的旧适配器。
修复后的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 rvMarket.adapter = adapter // 提前绑定适配器 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) { 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()) } Log.d("data-search", apiService.body().toString() ) } } catch (e: Exception) { e.printStackTrace() Log.d("$e", keyword ) } } } } private fun getMarketAccess() { val (savedToken, savedRefreshToken) = SharedPrefsUtil.getTokens(this@MarketAccessActivity) if (savedToken != null && savedRefreshToken != null) { 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() if (response.isSuccessful) { val marketResponse = response.body() marketResponse?.let { val marketList = marketResponse.data adapter.setItems(marketList) // 使用已初始化的适配器更新数据 Log.d("data-muncul",response.body()?.data.toString()) } } else { 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() Toast.makeText(this@MarketAccessActivity, "Failed to fetch lands", Toast.LENGTH_SHORT).show() Log.e("GetMarketsError", t.toString()) } }) } } }
内容的提问来源于stack exchange,提问作者rifqi padi siliwangi
相关产品推荐
相关产品推荐

