Android: 异步任务线程休眠错误

Android: Async Task Thread Sleep Error

我在 Whosebug 的职业生涯中遇到了第一个问题。我希望你能帮助我。

发生了什么:

我有片段,我想在其中设置一些带有一些日期的 recyclerView,它一直有效,直到我想用一些 ErrorMgs 做 ProgressDialog。

这是我的 onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.recycler_view, container, false);
    recyclerView = (RecyclerView) view.findViewById(R.id.my_recycler_view);
    textViewErrorMsg = (TextView) view.findViewById(R.id.tv_error_message);
    progressBarLoading = (ProgressBar) view.findViewById(R.id.pb_loading);
    new TakeDates().execute();
    return view;
}



我添加 AsyncTask:

@SuppressLint("StaticFieldLeak")
class TakeDates extends AsyncTask<Void, Void, Void> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog = new ProgressDialog(getActivity());
        progressDialog.getWindow().clearFlags(
                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        progressDialog.setMessage("Loading places...");
        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.show();
    }

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            Thread.sleep(2200);
            populateFromJson();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        if (progressDialog.isShowing())
            progressDialog.dismiss();
    }

}



最后一个方法是 populateFromJson:

 private void populateFromJson() {
    ConnectivityManager conMgr = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
    assert conMgr != null;
    NetworkInfo i = conMgr.getActiveNetworkInfo();
    if (i != null && i.isConnected() && i.isAvailable()) {
        ApiService api = RetroClient.getApiService(PLACES_URL);

        Call<PlaceList> call = api.getMyJSON();

        call.enqueue(new Callback<PlaceList>() {
            @Override
            public void onResponse(Call<PlaceList> call, Response<PlaceList> response) {
                if (response.isSuccessful()) {
                    itemList = response.body().getItemList();
                    adapter = new RecyclerViewPlaceAdapter(itemList, getContext());
                    recyclerView.setAdapter(adapter);
                    recyclerView.setHasFixedSize(true);
                    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
                    showPlaces();
                } else {
                    showErrorMessage("Try to restart your app.");
                }
            }

            @Override
            public void onFailure(Call<PlaceList> call, Throwable t) {
                showErrorMessage("Here is the main error: " + t.getMessage() + "\nTry to restart your app.");
            }
        });
    } else {
        showErrorMessage("Internet Connection Not Available" + "\nTry to find better connection to the internet.");
    }
}



现在关于错误:
1) 原因:android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触及它的视图。
我知道错误的主要部分在这里:
添加后 SLEEP Make ERROR

@Override
    protected Void doInBackground(Void... voids) {
        try {
            Thread.sleep(2200); 
            populateFromJson();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

不,错误的根本原因是您正在尝试使用来自工作线程的视图。 应该在这个方法中得到你的调用结果

@Override
protected void onPostExecute(Void result) {
  //work with you RecyclerView here
}

不要使用 AsyncTask。只需在 onCreateView() 中调用 populateFromJson()

populateFromJson() 尝试使用 recicleView。 View(和 View 子类)对象不能从除 Activity 线程之外的任何线程使用。

当您在 AsyncTask 上执行 .execute() 时,onPreExecuteonPostExecute 将由 activity 线程执行,而 doInBackground 将由子线程执行。

一旦你明白了这一点,你就会很容易理解,为了避免这个错误,你应该在 onPostExecute

中调用 populateFromJson()

N.B。如果您的 doInBackground 方法真的需要等待,那么有更有效的方法可以做到这一点。看看here and here

你不能从后台线程更新视图,让你的异步任务 return doInBackground 中的项目列表,onPostExecuted 将接收列表作为参数,你可以从该方法更新回收器视图.

一个更简单的方法是用 rxjava 替换异步任务