从另一个线程刷新 RecyclerView 导致错误

Refreshing RecyclerView from another thread causing error

我有项目数组列表已在另一个 activity 中更新,因为我 return 来自 activity,我想用全新的 ArrayList() 刷新我的 recyclerview。为了避免滞后,我将此刷新放在其他可运行线程上,并将 ProgressBar 而不是 RecyclerView。

在新线程中,此方法在适配器内部调用 (recyclerViewAdapter.adapterRefreshFoods())

fun adapterRefreshFoods(filteredList: ArrayList<Food>){
        if (!filteredList.isEmpty()){
            foodList = filteredList
            notifyDataSetChanged()
        }
    }

这导致以下异常。 (当我在 UIThread 中刷新它时它工作正常)

java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling android.support.v7.widget.RecyclerView

所有 UI 组件只能通过主线程访问,因为 UI 元素不是线程安全的,主线程是它的所有者。

mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message inputMessage) {

     //Call your UI related method

    }
}

参考:https://developer.android.com/training/multiple-threads/communicate-ui#java

您只能从 UI/Main 线程与 UI 元素交互。

下面的代码应该 post 您在 UI 线程上的操作:

fun adapterRefreshFoods(filteredList: ArrayList<Food>){
    if (!filteredList.isEmpty()){
        foodList = filteredList
        Handler(Looper.getMainLooper()).post { 
            // Code here will run in UI thread
            notifyDataSetChanged()
        }
    }
}

您永远不应该从 main/UI 线程以外的线程访问 UI 元素。您可以使用 AsyncTask 在后台加载数据并使用 publishProgress()onProgressUpdate().

连续更新 UI
    new AsyncTask<Void, List<YourDataClass>, List<YourDataClass>>(){
        @Override
        protected List<YourDataClass> doInBackground(Void... voids) {
            // Fetch data here and call publishProgress() to invoke
            // onProgressUpdate() on the UI thread.
            publishProgress(dataList);
            return dataList;
        }

        @Override
        protected void onProgressUpdate(List<YourDataClass>... values) {
            // This is called on the UI thread when you call 
            // publishProgress() from doInBackground()
        }

        @Override
        protected void onPostExecute(List<YourDataClass> dataList) {
            // This is called on the UI thread when doInBackground() returns, with
            // the result as the parameter
        }
    }.execute();