Skip to main content

About this widget

Use the Hits view and helper components to display a list of search results. Use HitsPaging if you want to use infinite scrolling in your search. To add Hits to your search experience, use these components:
  • Searcher. The Searcher that handles your searches.
  • T. A data class representing a search result.
  • HitsView<T>. The view that renders objects of type T.
See also:

Explore example code

Browse the Hits example code on GitHub.

Examples

You can use deserialize to convert raw hits into your own data class using the Serializable annotation.
Kotlin
class MyActivity : AppCompatActivity() {

    val searcher = HitsSearcher(
        applicationID = "YourApplicationID",
        apiKey = "YourSearchOnlyAPIKey",
        indexName = "YourIndexName"
    )
    val connection = ConnectionHandler()
    val adapter = MovieAdapter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        connection += searcher.connectHitsView(adapter) { response ->
            response.hits.deserialize(Movie.serializer())
        }
        searcher.searchAsync()
    }

    override fun onDestroy() {
        super.onDestroy()
        connection.disconnect()
        searcher.cancel()
    }
}

@Serializable
data class Movie(
    val title: String
)

class MovieViewHolder(val view: TextView): RecyclerView.ViewHolder(view) {

    fun bind(data: Movie) {
        view.text = data.title
    }
}

class MovieAdapter : RecyclerView.Adapter<MovieViewHolder>(), HitsView<Movie> {

    private var movies: List<Movie> = listOf()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
        return MovieViewHolder(TextView(parent.context))
    }

    override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
        val movie = movies[position]

        holder.bind(movie)
    }

    override fun setHits(hits: List<Movie>) {
        movies = hits
        notifyDataSetChanged()
    }

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

Compose UI

InstantSearch provides the LoadingState as a state model, which is an implementation of the LoadingView interface. You need to connect LoadingState to the LoadingConnector or LoadingViewModel like any other LoadingView implementation.
Kotlin
class MyActivity : AppCompatActivity() {
    val searcher = HitsSearcher(
        applicationID = "YourApplicationID",
        apiKey = "YourSearchOnlyAPIKey",
        indexName = "YourIndexName"
    )
    val hitsState = HitsState<Movie>()
    val connections = ConnectionHandler()

    init {
        connections += searcher.connectHitsView(hitsState) {
            it.hits.deserialize(Movie.serializer())
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LazyColumn {
                items(hitsState.hits) { movie ->
                    Text(movie.title)
                }
            }
        }
        searcher.searchAsync()
    }

    override fun onDestroy() {
        super.onDestroy()
        connections.disconnect()
        searcher.cancel()
    }
}

Parameters

transform
(SearchResponse) -> List<T>
required
A function transforming the search response into a list of results of your class T.
Kotlin
import com.algolia.client.model.search.SearchResponse

val transform: (SearchResponse) -> List<Movie> = { response ->
    response.hits.map { hit -> Movie(hit.json.getPrimitive("title").content) }
}
searcher.connectHitsView(adapter, transform)
Last modified on March 23, 2026