I am trying to show a progress indicator in some time consuming code but the screen is not refreshed while the code is running. After the code is finished it animates the indicator.
The solution is probably simple for an experienced android developer which I am not.
I created a minimum code application to show the problem

activity_main. html:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@android:color/black">
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="#FFFFFF"
            android:textSize="18sp"
            android:text="Start"
            tools:ignore="HardcodedText" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal">
            <com.google.android.material.progressindicator.CircularProgressIndicator
                android:id="@+id/cpi"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:progress="0"
                android:useLevel="true"
                android:visibility="visible"
                app:indicatorColor="#FF0000"
                app:indicatorSize="95dp"
                app:trackColor="#606060"
                app:trackCornerRadius="5dp"
                app:trackThickness="16dp"
                tools:layout_editor_absoluteX="157dp"
                tools:layout_editor_absoluteY="108dp" />
        </LinearLayout>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java:

package com.hennep.testcircularprogress;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.os.Handler;
import com.google.android.material.progressindicator.CircularProgressIndicator;

public class MainActivity extends AppCompatActivity {
    int iProgress = 0;

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

        final Button button = findViewById(R.id.button);
        final CircularProgressIndicator progress = findViewById(R.id.cpi);

        Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true ) {
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            progress.setProgress(iProgress,true);
                        }
                    },100 );
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e ) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();


        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v ) {
                iProgress = 0;
                //progress.setVisibility( CircularProgressIndicator.VISIBLE );
                button.setText("Calculating...");
                for( int k = 0; k < 192; k++ ) {
                    Thread.yield();
                    for( int fk = 1; fk <= 1000; fk *= 10 ) {
                        for( int j = 0; j < 192; j++ ) {
                            for( int fj = 1; fj <= 1000; fj *= 10 ) {
                                for( int i = 0; i < 192; i++ ) {
                                    for( int fi = 1; fi <= 1000; fi *= 10 ) {
                                        // Calculate E192 three resistor resistive divider here, not relevant for the test
                                        iProgress = k;
                                    }
                                }
                            }
                        }
                    }
                }
                button.setText("Start");
                //progress.setVisibility( CircularProgressIndicator.GONE );
            }
        });        
    }
}

而且按钮上的文本也没有改变,我预计也是同样的问题.

推荐答案

您正在主UI线程上运行计算,从而导致"停滞"UI行为. 按钮onClick处理程序在UI线程上执行. 请记住,只有一个UI线程-因此如果它忙于进行计算,则无法刷新显示.

以下是一些改进:

(1)首先可以将UI进度更新简化为自武装可运行(在UI线程上运行),每100 MS更新一次进度. 注意:不睡觉. 当进度达到100时自动终止. 按下按钮时启动. 它还通过一些反馈更新按钮.

    Button b = findViewById(R.id.button);

    // The "new Handler()" is deprecated.
    Handler handler = new Handler(Looper.getMainLooper());
    Runnable r = new Runnable() {

        @Override
        public void run() {
            progress.setProgress(iProgress);
            if (iProgress < 100) {
                handler.postDelayed(this, 100);
                b.setText(String.format("RUNNING: %d", iProgress));
            }
        }
    };

    // The handler progress updater is started when button is pressed (below)

(2)使用按钮处理启动新线程(根据定义不在UI线程上)来执行计算、更新进度并根据需要更新按钮.

    b.setText("Start");

    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            b.setText("Running");
            b.setEnabled(false);

            iProgress = 0;
            // start the progress updater
            handler.postDelayed(r, 100);

            new Thread(new Runnable() {
                @Override
                public void run() {
                    long d = System.currentTimeMillis();
                    for (int k = 0; k <= 100; k++) {
                        for (int j = 1; j < 100_000_000; j++) {
                            // some calculation
                            double x = (double) d / j;
                        }
                        iProgress = k;
                    }

                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            b.setText("Done - Restart");
                            b.setEnabled(true);
                        }
                    });
                }
            }).start();
        }
    });

结果:

enter image description here

Java相关问答推荐

如何在Java中对自定义协议进行主机名验证?

Gmail Javi API批量处理太多请求

inteliJ中是否有一个功能可以自动在块注释中的/*后面添加一个空格?''

DTO到实体,反之亦然,控制器和服务之间的哪一层应该处理转换?

为什么不应用类型推断?

我不能再在Android Studio Hedgehog上用Java语言创建新项目了吗?

Java:使用Class.cast()将对象转换为原始数组

Com.example.service.QuestionService中的构造函数的参数0需要找不到的类型为';com.example.Dao.QuestionDao;的Bean

JDK 21-为什么线程局部随机S nextInt不直接用Super.nextInt实现?

带错误BER验证的itext8签名返回pdf

Java Mooc.fi Part 12_01.Hideout -返回和删除方法

使用多个RemoteDatabase对象的一个线程

如何在Cosmos DB(Java SDK)中增加默认响应大小

Java17支持哪个MapR版本?

无法在IntStream上应用Collectors.groupingBy

在具有Quarkus Panache的PostgreSQL中将JSON数据存储为JSONB时,会将其存储为转义字符串

简化每个元素本身都是 map 列表的列表

为什么child-pom会创建一个新版本

窗口启动后不久,从java.awt.Graphics disapear创建的矩形

UuidGenerator Bean 类型不匹配?