【问题标题】:How to show a progress bar, when using ExecutorService's awaitTermination method?使用 ExecutorService 的 awaitTermination 方法时如何显示进度条?
【发布时间】:2021-01-31 09:29:36
【问题描述】:

我正在构建一个应用程序,它从多个网页中抓取价格,然后在所有任务完成后显示结果。一切正常,除了我正在努力添加进度条。

以下是我正在尝试做的简化版本。按下按钮后,程序运行 2 个任务:第一个任务休眠 3 秒,第二个任务 - 7 秒。全部完成后,将显示来自每个任务的 toast 消息。

公共类 MainActivity 扩展 AppCompatActivity {

Button button;
ProgressBar progressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    button = findViewById(R.id.btn);
    progressBar = findViewById(R.id.pb);

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            progressBar.setVisibility(View.VISIBLE);

            ExecutorService executorService = Executors.newFixedThreadPool(5);

            executorService.submit(new Task1());
            executorService.submit(new Task2());

            executorService.shutdown();

            try {
                executorService.awaitTermination(1, TimeUnit.MINUTES);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            progressBar.setVisibility(View.INVISIBLE);

        }
    });



}

private class Task1 implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(3000);
            Log.d("task1", "run: ");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "task1", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

private class Task2 implements Runnable {

    @Override
    public void run() {
        try {
            Log.d("task2", "run: ");
            Thread.sleep(7000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "task2", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

}

据我了解,问题是使用 awaitTermination 方法时所有线程都被阻塞,包括 UI 线程,因此只有在所有任务完成后才会显示任务结果。

有没有办法等到所有任务完成,同时仍然显示进度条?

【问题讨论】:

    标签: android concurrency executorservice android-progressbar


    【解决方案1】:

    是的,您对awaitTermination 的看法是正确的。但是它只阻塞了主线程,其他的都没有。

    解决问题的一种方法是定义活动任务计数器。每次运行任务时,它都会增加。每次任务结束(包括失败)计数器都会减少。

    当然你应该删除awaitTermination 方法。在 Android 中(主要是在所有与 UI 相关的框架中),您不应阻塞 UI 线程。

    我的命题的伪代码:

    Button button;
    ProgressBar progressBar;
    int activeTaskCounter = 0;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        button = findViewById(R.id.btn);
        progressBar = findViewById(R.id.pb);
    
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ExecutorService executorService = Executors.newFixedThreadPool(5);
    
                executorService.submit(new Task1());
                executorService.submit(new Task2());
                executorService.shutdown();
            }
        });
    }
    
    private void increaseActiveCounter() {
        activeTaskCounter += 1;
        progressBar.setVisibility(View.VISIBLE);
    }
    
    private void decreaseActiveCounter() {
        activeTaskCounter -= 1;
        if (activeTaskCounter == 0) {
            progressBar.setVisibility(View.INVISIBLE);
        }
    }
    
    private class Task1 implements Runnable {
        @Override
        public void run() {
            // It's lambda here, but you can use anonymous class. It's up to you
            runOnUiThread(() -> increaseCounter());
            try {
                Thread.sleep(3000);
                Log.d("task1", "run: ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                runOnUiThread(() -> decreaseActiveCounter());
            }
           
        }
    }
    
    private class Task2 implements Runnable {
    
        @Override
        public void run() {
            runOnUiThread(() -> increaseCounter());
            try {
                Thread.sleep(7000);
                Log.d("task2", "run: ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                runOnUiThread(() -> decreaseActiveCounter());
            }
        }
    }
    

    【讨论】:

    • 谢谢,它在提供的示例中确实有效。有什么方法可以保留 awaitTermination 功能,同时仍显示进度条?我使用 await 终止的原因是等到所有必要的数据都加载完毕,然后才显示在 UI 中。
    • 当 activeTaskCoubter 变为零时,您可以显示您的数据,因为它已加载。它和 awaitTermination 一样,但是是异步的。
    猜你喜欢
    • 2015-02-02
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多