Thread.sleep 的主线程正在冻结应用程序,android

Thread.sleep of main thread is freezing the app, android

所以问题是我想在作业中模仿冒泡排序算法的过程。我想要这样做的方式是 - 播放第一个淡出动画,然后停止我的 for 循环,等到动画完成,重新分配值,播放第二个动画,等到它完成并恢复 for 循环。我找到 Thread.sleep() 但最后我的应用程序冻结或屏幕黑屏,直到所有动画完成。我做了很多实验,所以我的代码看起来很糟糕(抱歉)。

public class BubbleSort extends AppCompatActivity {

    Button element1;
    Button element2;
    Animation fadeIn;
    Animation fadeOut;
    int[] values;

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

        fadeIn = AnimationUtils.loadAnimation(getApplicationContext(),
                R.anim.fade_in);
        fadeOut = AnimationUtils.loadAnimation(getApplicationContext(),
                R.anim.fade_out);

    }


    public void onSort(View view){
        HashMap<Integer, Integer> indexes = sort();
        Set<Integer> keySet = indexes.keySet();
        Integer[] keys  =  keySet.toArray(new Integer[keySet.size()]);
        for (int key : keys) {
            initElements(key, indexes.get(key));
            element1.startAnimation(fadeOut);
            element2.startAnimation(fadeOut);
            try {
                Thread.sleep(2000);
                element1.startAnimation(fadeIn);
                element1.setText("" + values[key]);
                element2.startAnimation(fadeIn);
                element2.setText("" + values[indexes.get(key)]);
            } catch (Exception e) {
                Log.i("test", e.toString());
            }
        }
    }

    void initElements(int from, int to){
        switch (from){
            case 0:{
                element1 = (Button) findViewById(R.id.element_1);
                break;
            }
            case 1:{
                element1 = (Button) findViewById(R.id.element_2);
                break;
            }
            case 2:{
                element1 = (Button) findViewById(R.id.element_3);
                break;
            }
            case 3:{
                element1 = (Button) findViewById(R.id.element_4);
                break;
            }
            case 4:{
                element1 = (Button) findViewById(R.id.element_5);
                break;
            }
            case 5:{
                element1 = (Button) findViewById(R.id.element_6);
                break;
            }
            case 6:{
                element1 = (Button) findViewById(R.id.element_7);
                break;
            }
            case 7:{
                element1 = (Button) findViewById(R.id.element_8);
                break;
            }
            case 8:{
                element1 = (Button) findViewById(R.id.element_9);
                break;
            }
            case 9:{
                element1 = (Button) findViewById(R.id.element_10);
                break;
            }
            default:{
                element1 = null;
                break;
            }
        }

        switch (to){
            case 0:{
                element2 = (Button) findViewById(R.id.element_1);
                break;
            }
            case 1:{
                element2 = (Button) findViewById(R.id.element_2);
                break;
            }
            case 2:{
                element2 = (Button) findViewById(R.id.element_3);
                break;
            }
            case 3:{
                element2 = (Button) findViewById(R.id.element_4);
                break;
            }
            case 4:{
                element2 = (Button) findViewById(R.id.element_5);
                break;
            }
            case 5:{
                element2 = (Button) findViewById(R.id.element_6);
                break;
            }
            case 6:{
                element2 = (Button) findViewById(R.id.element_7);
                break;
            }
            case 7:{
                element2 = (Button) findViewById(R.id.element_8);
                break;
            }
            case 8:{
                element2 = (Button) findViewById(R.id.element_9);
                break;
            }
            case 9:{
                element2 = (Button) findViewById(R.id.element_10);
                break;
            }
            default:{
                element2 = null;
                break;
            }
        }
    }

    HashMap<Integer, Integer> sort(){
        HashMap<Integer, Integer> indexes = new HashMap<>();
        values = new int[10];
        boolean sorting = true;
        int loop = 1;
        Random random = new Random();

        for (int index = 0; index < values.length; index++){
            values[index] = random.nextInt(10);
        }

        int offset = 0;
        while (sorting){

            System.out.println("To sort:");
            for (int element : values)
                System.out.print(" " + element);
            System.out.println();

            sorting = false;
            for (int index = 0; index < values.length - 1 - offset; index++) {
                if (values[index] > values[index + 1]) {
                    int temp = values[index];
                    values[index] = values[index + 1];
                    values[index + 1] = temp;
                    sorting = true;
                    indexes.put(index, index + 1);
                }
            }

            System.out.println("Loop: " + loop);

            for (int element : values)
                System.out.print(" " + element);
            System.out.println();

            loop++;
            offset++;
        }
        return indexes;
    }
}

从不 在主线程上使用 Thread.sleep。主线程是主线程(很明显)所以在主线程上休眠是 Android OS 认为是 A 应用程序 N ot R如果你睡得太久就会有反应。一般来说,如果可以的话,你应该避免在主线程上阻塞任务。

使用第二个线程可以休眠。您可以使用新的 Thread 实例或使用 AsyncTask。

同样适用于 runOnUiThread(运行 在来自不同线程的主线程上):永远不要使用 Thread.sleep。您的应用程序将收到 ANR,因为您阻止了主线程的执行。如果您想在继续之前休眠 2 秒,请使用不同的线程 (you can read more about it here)


自定义线程的一个示例是创建一个新的 class(尽管您也可以创建一个匿名的 class):

public class HelloThread extends Thread {
    boolean running;
    //Constructor to get variables. 
    public void run() {
        while(running){
            //While loop is optional, if you have for an instance a game thread you need a while-loop
            //to keep executing the code
        }
    }

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

}

或者如我之前所说,匿名 class:

Thread t = new Thread(){
    @Override
    public void run() {
        super.run();
        //It is harder to get variables into here though. Declare a "running" boolean
        //In the class if you want repetitive execution
    }
 };

从主线程使用 Thread.sleep() 导致应用程序冻结,使用如下动画回调:

fadeIn = AnimationUtils.loadAnimation(getApplicationContext(),
            R.anim.fade_in);
fadeIn.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {

        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });