当耗时的代码完成时,CircularProgressIndicator 显示得太晚了

问题描述 投票:0回答:1

我试图在一些耗时的代码中显示进度指示器,但代码运行时屏幕没有刷新。代码完成后,它会为指示器设置动画。
对于经验丰富的 Android 开发人员来说,解决方案可能很简单,但我不是。
我创建了一个最小代码应用程序来显示问题

activity_main.xml:

<?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 );
            }
        });        
    }
}

按钮上的文字也没有改变,我希望这是同样的问题。

java android progress-indicator
1个回答
0
投票

您正在主 UI 线程上运行计算,这会导致 UI 行为“停滞”。按钮

onClick
处理程序在 UI 线程上执行。请记住,只有一个 UI 线程 - 因此,如果它正忙于进行计算,则无法刷新显示。

以下是一些改进:

(1) 首先,UI 进度更新可以简化为一个自武装的可运行程序(在 UI 线程上运行),每 100MS 更新一次进度。注意:不睡觉。当进度达到 100 时自动终止。按下按钮时启动。

    // 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);
            }
        }
    };

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

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

    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() {
                    for (int k = 0; k <= 100; k++) {
                        for (int j = 1; j < 100_000_000; j++) {
                            // some calculation
                            double x = Math.PI / j;
                        }
                        iProgress = k;
                    }

                    runOnUiThread(new Runnable() {

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

结果:

© www.soinside.com 2019 - 2024. All rights reserved.