1. Preface
Recently, the fuzzy search function in the project is very difficult at first, but it's nothing to think about it carefully, because the specific fuzzy search part is the interface provided by the back end, and what we need to do is to perform the search function once when the content of the search box changes.
2. Renderings
Can see
- The text box searches in real time as you enter
- When there are no search results, the result display at the bottom is directly hidden
- Maotai is not strong
3. Ideas
-
The search box part uses EditText and listens to it through the addTextChangedListener method
-
In the interface part, I use Baidu's interface to simply realize the network request through Retrofit2
-
In the fuzzy search result display part, I use Recyclerview to display the fuzzy search results
4. Realization
4.1 EditText monitoring part
Method interpretation:
The addTextChangedListener of EditText listens as follows. You can see that there are three methods
-
beforeTextChanged()
This method is called once before EditText input
-
afterTextChanged()
Once the EditText input is completed, the method is called.
-
onTextChanged()
During EditText input, the method is called back continuously
etContent.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } })
Effect realization:
The effects we want to achieve are as follows
- When there is content in the input box, the delete button is displayed, and when there is no content, it is hidden
- Network requests are made continuously during the input process
- Recyclerview is displayed when there are search results, and hidden when there is no data
Specific implementation:
etContent.addTextChangedListener(object : TextWatcher { ...... override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { if (etContent.text.isNullOrEmpty()) { //If the input box is empty, the delete button is hidden ivDel.visibility = View.GONE //When the input box is empty, the recyclerview is hidden to hide the previous search results recy.visibility = View.GONE } else { //The input box is not empty. Delete the button display ivDel.visibility = View.VISIBLE //Make a network request when the input box changes mainViewModel.getFuzzySearchList(Const.fuzzySearchUrl,etContent.text.toString()) } } })
4.2 network request part
Interface part:
-
Fuzzy search
@GET request
Parameter: key: wd value: content to search
Address: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su
Using the above interface, just pass in a parameter wd, which is the content of our input box
interface ApiService { @GET fun getFuzzySearchList(@Url url:String,@Query("wd") content:String): Call<ResponseBody> }
-
Detail interface
Url is: http://www.baidu.com.cn/s?wd= +Text box content + & CL = 3
Here we simply load the page through webview
Logical part:
- After the request is completed, if the data is empty, the Recyclerview panel will be hidden, otherwise it will be displayed
- Update the Recyclerview after the request is completed
5. Concrete realization
MainActivity
class MainActivity : AppCompatActivity() { //Create ViewModel private val mainViewModel: MainViewModel by lazy { ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application)).get( MainViewModel::class.java ) } private val data = mutableListOf<String>() private val myAdapter = MyAdapter(data) override fun onCreate(savedInstanceState: Bundle?) { ... //Recyclerview related configurations recy.layoutManager = LinearLayoutManager(this) recy.adapter = myAdapter //Jump to details page myAdapter.setOnMyClickListener(object :MyAdapter.MyClickListener{ override fun onClick(position: Int) { val intent = Intent(this@MainActivity,NewsShowActivity::class.java) val url = Const.serchUrl+data[position]+"&cl=3" intent.putExtra("url",url) startActivity(intent) //After jump, clear the search box and hide the Recyclerview panel etContent.setText("") recy.visibility = View.GONE } //Fuzzy search result monitoring mainViewModel.getResultLiveData().observe(this, Observer { if(it.isEmpty()){ //If the data is empty, hide the RecyclerView panel recy.visibility = View.GONE }else{ recy.visibility = View.VISIBLE } //Update RecyclerView after search data.clear() data.addAll(it) myAdapter.notifyDataSetChanged() }) //EditText search box to listen etContent.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { if (etContent.text.isNullOrEmpty()) { ivDel.visibility = View.GONE //When it is empty, if it is not hidden, the results of the previous search will be displayed below and will not be hidden recy.visibility = View.GONE } else { ivDel.visibility = View.VISIBLE //Make a network request mainViewModel.getFuzzySearchList(Const.fuzzySearchUrl,etContent.text.toString()) } } }) } }
MainViewModel
The data returned by fuzzy search is in the following format and GBK coding, so we need to process the data after the request is successful
window.baidu.sug({q:"Olympic Games",p:false,s:["Olympic Games","Olympic women's 200m butterfly final","Olympic medal list","Olympic schedule","Olympic gold medal list 2021","Olympic table tennis","Live broadcast of the Olympic Games","How many years are the Olympic Games held","Where do you watch the Olympic Games","Olympic referee"]});
class MainViewModel :ViewModel(){ private val httpClient = OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) .readTimeout(5, TimeUnit.SECONDS) .writeTimeout(5, TimeUnit.SECONDS) .build() private val retrofit: Retrofit =Retrofit.Builder() .baseUrl("http://a") .client(httpClient) .addConverterFactory(GsonConverterFactory.create()) .build() private val api = retrofit.create(ApiService::class.java) /** * Fuzzy search */ fun getFuzzySearchList(url:String,content:String){ api.getFuzzySearchList(url,content).enqueue(object : retrofit2.Callback<ResponseBody> { override fun onFailure(call: Call<ResponseBody>, t: Throwable) { errorLiveData.value = t.message } override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) { if(response?.body() != null){ //Because the result of fuzzy search is GBK code, it needs to be processed here val charset = response.body()!!.contentType()!!.charset()!! val source = response?.body()?.source() source?.let { source.skip(ByteString.decodeHex("efbbbf").size().toLong()) } val string = response?.body()?.string() string?.let { val startIndex = it.indexOf("(") val endIndex = it.length-2 //intercept val json = it.substring(startIndex+1, endIndex) val jsonObject = gson.fromJson<ResultBean>(json, ResultBean::class.java) //Update data resultLiveData.value = jsonObject.s } } } }) } }
6. Summary
The above is the whole content. In fact, it's very simple. We actually listen to EditText and process the results of network requests. The logic of the rest is when to display and hide.
If this article is helpful to you, please don't forget Sanlian. If there are inappropriate places, please put forward them. See the next article.
7. Reference articles
Baidu fuzzy query_ Sanfanyu CSDN blog
Call Baidu search interface to query_ Great mind 829 column - CSDN blog
⭐Android retro fit requests to return String data. Chinese garbled code solution