Android: 如何在执行 long-运行 操作时显示微调器?

Android: How to show a spinner while performing a long-running operation?

我在 .xml 中有一个 ProgressBar,我想在长 运行 操作时显示它。我用

ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
progressSpinner.setVisibility(View.VISIBLE);

在某些 onButtonClick 方法中设置其可见性。如果上面的代码就是方法中的全部,那么它工作得很好。问题是当我有这样的方法时:

public void onButtonClick (android.view.View view){
    ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
    progressSpinner.setVisibility(View.VISIBLE);

    longRunningMethod(); // This method takes 5-10 seconds to run

    progressSpinner.setVisibility(View.GONE);
}

UI 只是锁定,直到 longRunningMethod 完成。该方法工作得很好,但微调器从未显示。

我在另一个线程上尝试了 运行 一切:

public void onButtonClick (android.view.View view){
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    executorService.submit(this::longRunningMethod);
}

并且我将微调器可见性更改内容添加到 longRunningMethod:

private void longRunningMethod(){
    ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
    progressSpinner.setVisibility(View.VISIBLE);

    // Logic that takes 5-10 seconds to run.

    progressSpinner.setVisibility(View.GONE);
}

当我执行此操作时,UI 不会锁定,但 longRunningMethod 中的任何内容都不起作用。微调器不会显示,逻辑似乎也不起作用,尽管这可能只是逻辑在非 UI 线程上运行不佳的问题。不过,我很困惑微调器的可见性不会从这里更新。

对于运行宁长任务操作,您应该使用工作线程。 您必须 运行 工作线程中的任务,然后 return 任务结果到 UI。

第一种方法是使用 AsyncTask:

AsyncTask was intended to enable proper and easy use of the UI thread. However, the most common use case was for integrating into UI, and that would cause Context leaks, missed callbacks, or crashes on configuration changes. It also has inconsistent behavior on different versions of the platform, swallows exceptions from doInBackground, and does not provide much utility over using Executors directly.

第二个是使用 Pure Thread

All Android apps use a main thread to handle UI operations. Calling long-running operations from this main thread can lead to freezes and unresponsiveness. For example, if your app makes a network request from the main thread, your app's UI is frozen until it receives the network response. You can create additional background threads to handle long-running operations while the main thread continues to handle UI updates.

official document

最后一个方法是使用 Coroutine(仅适用于 kotlin)

if you are using kotlin i suggest this one otherwise use AsyncTask

只需尝试 运行 您在其他线程中的任务和 return 使用接口之类的回调的结果

首先,我建议您熟悉 android 中的线程:

https://developer.android.com/guide/components/processes-and-threads

然后,有一些库来管理线程

AsyncTask,协程,Rxjava。 . .

采纳新浪的建议使用线程,class现在看起来像:

public class MainActivity extends AppCompatActivity{
    
    // Irrelevant code (fields, init, other button handlers, etc...)

    private void onButtonClick(android.view.View view){
        LongRunningThread longRunningThread = new LongRunningThread();
        longRunningThread.start();
    }

    private class LongRunningThread extends Thread{
        public void run(){
            runOnUiThread(MainActivity.this::showSpinner);

            // Logic that takes 5-10 seconds to run

            runOnUiThread(MainActivity.this::hideSpinner);
        }
    }

    private void showSpinner(){
        ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
        progressSpinner.setVisibility(View.VISIBLE);
    }

    private void hideSpinner(){
        ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
        progressSpinner.setVisibility(View.GONE);
    }

}

这样做会在 long-running 逻辑 运行ning 时显示进度微调器,然后在 long-running 逻辑完成后隐藏进度微调器。 UI 始终保持响应并且不会锁定。

与原来的代码相比,这里使用了Thread而不是ExecutorService。它还通过 AppCompatActivity.runOnUiThread().运行s UI 逻辑。

在不锁定 UI 的情况下,在 UI 更新的同时执行任何 long-running 任务的答案似乎是创建一个线程并调用 Thread.start( ).线程应包含 long-running 逻辑以及 UI 逻辑。该线程中的 UI 逻辑必须是 运行 使用 运行OnUiThread()。