【问题标题】:Show progress dialog during task without blocking UI thread in Android在任务期间显示进度对话框而不阻塞Android中的UI线程
【发布时间】:2021-09-21 18:17:40
【问题描述】:
@Override
protected void onCreate (Bundle savedInstanceState) {
    
    progressDialog.show();

    if (/* task that returns a boolean value */) {
        // Do stuff        
    }
    else {
        // Do other stuff     
    }

    progressDialog.dismiss();

}

这段代码应该显示进度对话框,等待任务产生结果,然后评估if 语句并关闭对话框。但这不会发生:UI 线程被阻塞,任务被执行,然后才显示进度对话框,然后立即关闭。

解决这个问题的正确方法是什么?

【问题讨论】:

    标签: java android asynchronous progressdialog oncreate


    【解决方案1】:

    一个简单的worker thread

    public void onClick(View v) {
        new Thread(new Runnable() {
            public void run() {
                // a potentially time consuming task
            }
        }).start();
    }
    

    根据answer 中提到的您的要求,可以考虑其他替代方案。

    【讨论】:

    • 似乎我必须将整个东西包装在其中一个中以将其与 UI 线程分开。谢谢!
    • 你不应该直接使用线程,使用为后台任务设计的各种实用程序。官方文档推荐 Coroutines for Kotlin 和 Java Concurrent utility for Java。还有一些用于后台处理的库。
    【解决方案2】:

    您可以为此目的使用 AsyncTask,但是,它在 Sdk 30 中已被弃用,建议直接使用 java.concurrent.* 实用程序docs。以下是使用 ExecutorService 的一种变通方法,虽然并不完美,但绝对满足您的功能:

    在您的 Activity(例如 MyActivity)中,创建 ExecutorService 的成员并对其进行初始化。添加方法和回调如下,当你想执行一些后台任务时,只需调用它:

    public class MyActivity extends AppCompatActivity {
        // You can use your preferred executor
        private final ExecutorService executor = new ThreadPoolExecutor(0, 1,
                3L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
    
        @Override
        protected void onCreate (Bundle savedInstanceState) {
            // Initiate the task
            executeParallel(new Callable<Boolean> {
                @Override
                public Boolean call() {
                    // Perform your task and return boolean
                    return trueOrFalse;
                }
            }, new Callback<Boolean>() {
                @Override
                public void onStart() {
                    // Show progress dialog
                    progressDialog.show();
                }
    
                @Override
                public void onComplete(Boolean result) {
                    if (result) {
                        // Do some tasks
                    } else {
                        // Do other tasks
                    }
                    // Remove dialog
                    progressDialog.dismiss();
                }
            }, new Handler(Looper.getMainLooper()));
        }
    
        public <R> void executeParallel(@NonNull Callable<R> callable, @Nullable Callback<R> callback, Handler handler) {
            executor.execute(() -> {
                handler.post(() -> {
                    if (callback != null) {
                        callback.onStart();
                    }
                });
                R r = null;
                try {
                    r = callable.call();
                } catch (Exception e) {
                    // Ignore
                } finally {
                    R result = r;
                    handler.post(() -> {
                        if (callback != null) {
                            callback.onComplete(result);
                        }
                    });
                }
            });
        }
    
        public interface Callback<R> {
            void onStart();
            void onComplete(R result);
        }
    }
    

    完成后,只需关闭 ExecutorService。如果您将其用于更好的设计,则可以将此 Executor 和相关方法移动到 ViewModel 中。请记住,您不应该直接使用 Thread 以避免潜在的内存泄漏。

    【讨论】:

    • 会发生什么样的内存泄漏?
    • 起初,你不能从后台线程更新你的 UI 元素,为了解决这个问题,有线程之间交互的 Handler。其次,如果您运行一个线程来执行长时间运行的任务并且发生配置更改,您的活动会被破坏,但线程会保持活动状态,使用系统资源并可能导致意外行为,除非您正确处理它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多