线程冻结 UI

发布于 2025-01-17 00:02:50 字数 1354 浏览 0 评论 0原文

我有一个按钮,当单击该按钮时,会调用 thead 来更新用户 ui:

averageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new Testing().execute();
        }
    });

该方法会被执行,但会将 UI 冻结 10 秒。我想每次调用averageMiles.append(mile)方法时更新UI。

    class Testing extends AsyncTask<Void, Void, Void> {
    @Override
    protected void onPostExecute(Void unused) {

        int x = 0;
        while (true) {

            if (x == 10) {
                break;
            }

            ArrayList<Double> milesList = new ArrayList<>();


            if (x == 0) {
                averageMiles.setText("mph: ");
            }

            String mile = milesValue.getText().toString();
            if (!isNum(mile)) {
                continue;
            }

            averageMiles.append(mile);
            milesList.add(Double.valueOf(mile.trim()));
            x++;
            if (x == 10) {
                averageMiles.append("\nAverage: " + getAverage(milesList));
                return ;
            } else {
                averageMiles.append(", ");
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }


    }

I have this button that when clicked calls a thead to update user ui:

averageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new Testing().execute();
        }
    });

The method gets executed but it freezes the UI for 10 seconds. I want to update the UI everytime I call the averageMiles.append(mile) method.

    class Testing extends AsyncTask<Void, Void, Void> {
    @Override
    protected void onPostExecute(Void unused) {

        int x = 0;
        while (true) {

            if (x == 10) {
                break;
            }

            ArrayList<Double> milesList = new ArrayList<>();


            if (x == 0) {
                averageMiles.setText("mph: ");
            }

            String mile = milesValue.getText().toString();
            if (!isNum(mile)) {
                continue;
            }

            averageMiles.append(mile);
            milesList.add(Double.valueOf(mile.trim()));
            x++;
            if (x == 10) {
                averageMiles.append("\nAverage: " + getAverage(milesList));
                return ;
            } else {
                averageMiles.append(", ");
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }


    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冷月断魂刀 2025-01-24 00:02:50

使用官方 oracle 和 android 开发人员文档中的 ThreadPool 执行器

Oracle 文档 - java.util.concurrent.ThreadPoolExecutor
Android 文档 - java.util.concurrent.ThreadPoolExecutor

如您所指定您使用的是 java,上面的两个文档是 google 推荐的,如下所示的 AsyncTask

此类在 API 级别 30 中已弃用。
请改用标准 java.util.concurrent 或 Kotlin 并发实用程序。

最终目标是 android 说,如果您想更新 UI,只需将 runOnUiThread 与更新 UI 的新可运行对象一起使用,这意味着对于每个 UI 更新,您可能会创建新的短期线程只更新 UI 和线程完成以及垃圾收集

示例代码

public class MainActivity extends AppCompatActivity {
    int count = 0;
    Executor ex;
    MyThread th;

    class MyThread extends Thread implements Runnable {
        private boolean running=false;

        public void setRunning(boolean running) {
            this.running = running;
        }

        @Override
        public void run() {
            while(running) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        count++;
                        TextView tv = findViewById(R.id.textView);
                        tv.setText(String.valueOf(count));
                    }
                });
            }
        }
    }

    public void onStartClick(View view) {
        th = new MyThread();
        ex = Executors.newSingleThreadExecutor();
        th.setRunning(true);
        ex.execute(th);
    }

    public void onStopClick(View view) {
        if(th!=null) {
            th.setRunning(false);
        }
    }
}

类的所有成员变量只能在 runOnUiThread 内部访问,例如 count++ count 是 MainActivity 的变量 如果你只需要在 MyThread 类中放置特定于线程的任何值

切勿尝试访问 run() 方法中的任何 MainActivity 变量

您还可以将 MyThread 编写为单独的类,并在启动线程之前设置类似于 th.setRunning 的值。

如果您想在线程完成后进行回调,请使用一个接口,该接口将为您提供 MainActivity 中的回调方法,

因此它只是核心 java
我创建了一个带有界面的示例
并发执行器接口示例

Use ThreadPool executor from official oracle and android developer documentations

Oracle Docs - java.util.concurrent.ThreadPoolExecutor
Android Docs - java.util.concurrent.ThreadPoolExecutor

as you have specified you are using java the above two documentation is recommended by google as show below for AsyncTask

This class was deprecated in API level 30.
Use the standard java.util.concurrent or Kotlin concurrency utilities instead.

The ultimate objective is the android is saying that, if you want to update UI, simply use runOnUiThread with a new runnable you update the UI, which means for each UI update you may be creating fresh short term thread which only updates the UI and thread finishes and garbage collected

Sample Code

public class MainActivity extends AppCompatActivity {
    int count = 0;
    Executor ex;
    MyThread th;

    class MyThread extends Thread implements Runnable {
        private boolean running=false;

        public void setRunning(boolean running) {
            this.running = running;
        }

        @Override
        public void run() {
            while(running) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        count++;
                        TextView tv = findViewById(R.id.textView);
                        tv.setText(String.valueOf(count));
                    }
                });
            }
        }
    }

    public void onStartClick(View view) {
        th = new MyThread();
        ex = Executors.newSingleThreadExecutor();
        th.setRunning(true);
        ex.execute(th);
    }

    public void onStopClick(View view) {
        if(th!=null) {
            th.setRunning(false);
        }
    }
}

all the member variables of the class should be only accessed inside runOnUiThread, for example count++ count is a variable of the MainActivity if you want any value specific to the thread you put only inside the MyThread class

Never try to access any of the MainActivity variable inside the run() method

You can also write MyThread as separate class, and set values similar to th.setRunning before starting the thread.

If you want a callback after the thread is completed use an interface which will give you a callback method in your MainActivity

So it is simply core java
I have created an example with interface
Concurrent Executor Interface Example

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文