【问题标题】:Why is AsyncTask working on the main thread?为什么 AsyncTask 在主线程上工作?
【发布时间】:2018-10-19 12:04:13
【问题描述】:

我正在尝试使用AsyncTask 在后台执行一项任务,然后在完成时显示它,但结果是在完成之前什么都没有显示。

我也尝试使用 execute 和 doInBackground 来调用它,但两者都会导致相同的问题,我必须等待活动开始一切就绪,而不是显示带有加载进度条的页面,然后添加稍后列出。

代码:

private class listTask extends AsyncTask<Void,Void,Void> {
    @Override
    protected Void doInBackground(Void... voids) {
        recyclerview.setAdapter(new ItemAdapter(getInternalFileList()));
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        progressbar.setVisibility(View.GONE);
    }

    List<GalleryItem> getInternalFileList(){
        String path = getActivity().getFilesDir().toString();
        File directory = new File(path);
        File[] files = directory.listFiles();
        List<GalleryItem> galleryItems = new ArrayList<>();

        MainDBRepository repo = new MainDBRepository(getActivity());
        HashMap<String,GalleryItem> itemsMap = repo.getItemsMap();

        for(File file : files) {
            if(itemsMap.containsKey(file.getName()))
                galleryItems.add(itemsMap.get(file.getName()));
        }

        Collections.reverse(galleryItems);

        return galleryItems;
    }

    private class ItemHolder extends RecyclerView.ViewHolder {
        ImageView mItemImageView;

        ItemHolder(View itemView) {
            super(itemView);
            mItemImageView = (ImageView) itemView.findViewById(R.id.image_view);
        }

        public void bindBackgroundImage(Bitmap backgroundImage){
            mItemImageView.setImageBitmap(backgroundImage);
        }

        public void bindImageViewer(final String path){
            mItemImageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = ImageViewerActivity.newIntent(getActivity(), path);
                    startActivity(intent);
                }
            });
        }
    }

    private class ItemAdapter extends RecyclerView.Adapter<ItemHolder> {
        private List<GalleryItem> galleryItems;

        ItemAdapter(List<GalleryItem> galleryItems) {
            galleryItems = galleryItems;
        }

        @NonNull
        @Override
        public ItemHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(getActivity());
            View v = inflater.inflate(R.layout.gallery_item, viewGroup, false);
            return new ItemHolder(v);
        }

        @Override
        public void onBindViewHolder(@NonNull ItemHolder itemHolder, int position) {
            GalleryItem galleryItem = galleryitems.get(position);
            String path = getActivity().getFilesDir() + "/" + galleryItem.getID();
            File file = new File(path);
            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
            itemHolder.bindBackgroundImage(bitmap);
            itemHolder.bindImageViewer(path);
        }

        @Override
        public int getItemCount() {
            return galleryitems.size();
        }
    }
}

【问题讨论】:

  • Asynctask 在主线程本身上工作。它被创建为在主线程上运行。
  • 如果你想在AsyncTask正在计算的时候显示一些东西,你应该实现onProgressUpdate(Progress... values)方法,该方法从publishProgress(Progress... values)调用并实现后台任务进度下的逻辑。
  • 请说明您如何调用异步任务。你没有使用.get() 是吗?
  • 第一次通话没问题。第二种是禁止的。永远不要那样做!
  • 此外,您最好只在 doInBackground() 中获取文件列表,并在 onPostExecute() 中创建和设置适配器。

标签: java android android-asynctask


【解决方案1】:

如果您想在 AsyncTask 计算后台任务时在 UI 中显示某些内容,您应该实现从 publishProgress(Progress... values) 调用的 onProgressUpdate(Progress... values) 方法并实现后台任务下的逻辑进步。在您的代码中,您只需在 onPostExecute() 中显示最终结果。请注意,AsyncTask 在与 UI 线程不同的线程中运行 doInBackground() 方法,在 UI 线程上运行 onProgressUpdate()onPostExecute(),因为它们应该更新 UI。有关详细信息,请参阅 Android 文档about AsyncTask

【讨论】:

  • 感谢您的回答,我不确定您是否正确,但我的意思是,片段本身在异步任务完成之前不会加载,片段有一个进度条默认情况下,我希望在 asynctask 完成之前首先显示,发生的情况是屏幕冻结,我必须等待片段在加载所有内容时出现。不应该使用 asynctask 让我在完成之前加载片段吗?
  • 片段有自己的生命周期,所以你只需要实现它们的onSomething() 方法来正确加载 UI 部分。 AsyncTasks 用于当您必须在后台执行“繁重”(需要大量时间)操作以避免 UI 冻结(不响应用户输入)时。我不认为使用AsyncTask 是解决您问题的正确方法。
  • 我猜我对 Asynctask 的理解有误,会尝试重新阅读文档,也许我会找到我的问题,谢谢
  • 好吧,继续。八!
  • 谁能解释一下为什么这个无关紧要的不切题的答案得到了这么多的支持?
【解决方案2】:

在后台只是意味着 - 而不是在 UI 上 - 线程。要在作业完成之前获得结果,您需要在后台执行作业时将结果提供给 UI 线程。在您可以使用 AsyncTask.onProgressUpdate(..) 之前在 UI 线程上获得结果 - 或者更好地使用 kotlin 协程而不是 asynctask。

【讨论】:

  • 感谢您的回答,我不确定您是否正确,但我的意思是,片段本身在异步任务完成之前不会加载,片段有一个进度条默认情况下,我希望在 asynctask 完成之前首先显示,发生的情况是屏幕冻结,我必须等待片段在加载所有内容时出现。不应该使用 asynctask 让我在完成之前加载片段吗?
猜你喜欢
  • 2015-08-16
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-14
  • 1970-01-01
相关资源
最近更新 更多