RecyclerView, loading data from Web-API: 如何防止RecyclerView初始为空?

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

我做了一个RecyclerView。初始数据是从 web-API 使用 Retrofit 加载的。因为缺少,是从服务器加载数据造成的,初始视图是空的。

目前我有一个 Thread.sleep() 用于延迟对 Recycler-View 适配器的数据分配。然后它按预期工作。请在代码中查看我的评论。

我怎样才能摆脱睡眠这个肮脏的把戏?这是如何正确完成的?

主要活动:

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)
        }
    }
}

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}")
            }
        })
    }
}

你无法摆脱来电的“等待时间”API。 事实上,让 UIThread 休眠或给它太多处理是一种非常糟糕的做法。 更糟糕的是,您的 API 可能需要 5 秒来加载数据,并且表现得好像没有数据一样。

更好的方法是在访问 activity 之前加载(因此您向用户显示一个进度条,告诉他在启动 activity 之前正在加载数据) 或者您可以在实际 activity 中显示一个进度条(例如,而不是 RecyclerView)。然后一旦你的数据被加载 (onSuccess),你可以 remove/hide 你的 progressBar 来设置适配器,或者调用 setData (这取决于你想要什么)

不要忘记处理 onFailure 场景的场景案例。