Home > OS >  RecyclerView, loading data from Web-API: How to prevent that the RecyclerView is initially empty?
RecyclerView, loading data from Web-API: How to prevent that the RecyclerView is initially empty?

Time:03-27

I have made a RecyclerView. The initial data is load with Retrofit from a web-API. Because of the lack, which is caused by loading the data from the server, the initial view is empty.

Currently I have a Thread.sleep() in there for delaying the data-assignment to the Recycler-View adapter. Then it works as expected. Please see my comment in the code.

How can I get rid of the dirty trick with the sleep? How is this done properly?

MainActivity:

class MainActivity : AppCompatActivity() {
    val TAG = MainActivity::class.java.simpleName
    lateinit var recyclerView: RecyclerView
    lateinit var addContactFab: FloatingActionButton
    lateinit var viewModel: ContactsViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        addContactFab = findViewById(R.id.addContactFab)
        recyclerView = findViewById(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)
        viewModel = ViewModelProvider(this).get(ContactsViewModel::class.java)
        // -- How can I get rid of this? ---
        Thread.sleep(1000) 
        // ---------------------------------
        recyclerView.adapter = ContactAdapter(viewModel.contactsList)

        addContactFab.setOnClickListener {
            val contact = Contact(id = System.currentTimeMillis(),
                name = "Test Name", email = "Test Email", phone = "${System.currentTimeMillis()}")
            viewModel.contactsList.add(contact)
            recyclerView.adapter = ContactAdapter(viewModel.contactsList)
        }
    }
}

The ViewModel-class:

class ContactsViewModel: ViewModel() {
    val TAG = this::class.java.simpleName
    var contactsList = ArrayList<Contact>()

    init {
        val retrofit = Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("https://jsonplaceholder.typicode.com")
            .build()
        val service = retrofit.create(ApiInterface::class.java)
        val call = service.getContacts()

        call.enqueue(object : Callback<List<Contact>> {
            override fun onResponse(call: Call<List<Contact>>, response: Response<List<Contact>>) {
                if (response.code() == 200) {
                    val contacts = response.body()
                    contacts?.forEach {
                        contactsList.add(Contact(
                            id = it.id,
                            name = it.name,
                            email = it.email,
                            phone = it.phone))
                    }
                }
            }

            override fun onFailure(call: Call<List<Contact>>, t: Throwable) {
                Log.d(TAG, "onFailure: ${t.localizedMessage}")
            }
        })
    }
}

CodePudding user response:

You can't rid of the "waiting time" for the call API. Indeed, it is a very bad practice to sleep the UIThread or give it so much processing. Worse here, your API may take 5sec for example to load the data, and act like there is no data.

The better thing is either load before to access to the activity (so you show a progressBar to the user telling him that the data is loading before launching the activity) Or you may show a progressBar for example into your actual activity (instead of the RecyclerView for example). Then once your data are loaded (onSuccess), you can remove/hide your progressBar to set the adapter, or call setData (it depends on what you want)

Don't forget also to handle the scenario case for onFailure scenario.

  • Related